C++ 在C+;中按值返回构造的对象时避免复制构造函数调用+;11

C++ 在C+;中按值返回构造的对象时避免复制构造函数调用+;11,c++,c++11,C++,C++11,我有一个没有复制构造函数的类,我仍然希望通过值返回它。以下MCVE在C++17中编译: class Cls { public: Cls(int x) {} Cls(const Cls& c) = delete; }; Cls f(int x) { return Cls(x); } int main() { f(0); } 但不是在C++11中: $ g++ prog.cc -Wall -Wextra -std=c++11 prog.cc: I

我有一个没有复制构造函数的类,我仍然希望通过值返回它。以下MCVE在C++17中编译:

class Cls {
    public:
    Cls(int x) {}
    Cls(const Cls& c) = delete;
};

Cls f(int x) {
    return Cls(x);
}

int main() {
    f(0);
}
但不是在C++11中:

$ g++ prog.cc -Wall -Wextra -std=c++11
prog.cc: In function 'Cls f(int)':
prog.cc:9:17: error: use of deleted function 'Cls::Cls(const Cls&)'
    9 |     return Cls(x);
      |                 ^
prog.cc:5:5: note: declared here
    5 |     Cls(const Cls& c) = delete;
      |     ^~~
据我所知,原因是编译器不允许优化复制,即使在这种情况下它应该是微不足道的

我希望
返回std::move(Cls(x))
可以工作并避免复制构造函数,但它会给出相同的错误

我是否可以在不定义复制构造函数(或assignment运算符)的情况下修复此问题


我已经查看了相关问题,但没有找到重复的问题。

改为实现移动构造函数

在C++17中,编译器必须复制或移动对象,而不必复制或移动对象。但对于C++11,您没有此功能,但您可以为您的案例采取行动:

Cls(Cls&& c) = default;
据我所知,原因是编译器不允许优化复制,即使在这种情况下它应该是微不足道的

没错

我希望返回std::move(Cls(x));将工作并避免复制构造函数,但它会给出相同的错误

这不是解决办法<代码>标准::移动(Cls(x))不会做任何事情,因为
Cls(x)
已经生成一个pr值。在极少数情况下,如返回函数参数时,应将返回值转换为右值。此外,如果可以从该右值移动并构造另一个实例,则只能使用
Cls
右值而不进行复制,而在原始代码段中则不是这样

我是否可以在不定义复制构造函数(或assignment运算符)的情况下修复此问题

您可以按照的建议定义移动构造函数。这允许返回类型为
Cls
的临时对象,但仍不允许复制。您将其称为仅移动类型,而仅移动的主要标准类型之一是
std::unique_ptr

最后一点,我认为这是一个很好的实践,建议处理移动构造/分配,不要依赖于隐式删除这些特殊的成员函数

我是否可以在不定义复制构造函数(或assignment运算符)的情况下修复此问题

在您的案例中有两个选项:

Cls(Cls&& c) = default;
  • 定义移动构造函数:

    Cls(Cls&& c) = default;
    
    Cls f(int x) {
        return {x};
    }
    
  • Use,它允许不调用复制/移动构造函数,它需要一个非显式构造函数:

    Cls(Cls&& c) = default;
    
    Cls f(int x) {
        return {x};
    }
    


在C++17中,您有“保证”复制省略(或“非物质化值传递”),因此
返回Cls(x)就可以了。

即使编译器可以省略副本(因此不会调用实际的副本构造函数),也需要一个副本构造函数。您明确禁止复制您的类型。“在C++17中,编译器可以做”-编译器实际上需要这样做。@Fureeish确实是。