Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/137.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 链接时如何避免复制?_C++_C++14_C++17_Reference_Value_Copy Elision - Fatal编程技术网

C++ 链接时如何避免复制?

C++ 链接时如何避免复制?,c++,c++14,c++17,reference,value,copy-elision,C++,C++14,C++17,Reference,Value,Copy Elision,我正在创建一个链接类型的类,如下面的小示例。似乎在链接成员函数时,会调用复制构造函数。有没有办法摆脱复制构造函数调用?在我下面的玩具示例中,很明显,我只处理临时性的问题,因此“应该”(可能不是按照标准,而是逻辑上)是一个省略。第二个最佳选择是复制省略,即调用move构造函数,但事实并非如此 class test_class { private: int i = 5; public: test_class(int i) : i(i) {} test_clas

我正在创建一个链接类型的类,如下面的小示例。似乎在链接成员函数时,会调用复制构造函数。有没有办法摆脱复制构造函数调用?在我下面的玩具示例中,很明显,我只处理临时性的问题,因此“应该”(可能不是按照标准,而是逻辑上)是一个省略。第二个最佳选择是复制省略,即调用move构造函数,但事实并非如此

class test_class {
    private:
    int i = 5;
    public:
    test_class(int i) : i(i) {}
    test_class(const test_class& t) {
        i = t.i;
        std::cout << "Copy constructor"<< std::endl;
    }
    test_class(test_class&& t) {
        i = t.i;
        std::cout << "Move constructor"<< std::endl;
    }
    auto& increment(){
        i++;
        return *this;
    }
};
int main()
{
    //test_class a{7};
    //does not call copy constructor
    auto b = test_class{7};
    //calls copy constructor
    auto b2 = test_class{7}.increment();
    return 0;
}
类测试\u类{
私人:
int i=5;
公众:
测试类(inti):i(i){
测试等级(常数测试等级和t){
i=t.i;
标准::cout
  • 部分回答(它不会就地构造
    b2
    ,而是将复制构造转换为移动构造):您可以在关联实例的值类别上重载
    increment
    成员函数:

    auto& increment() & {
        i++;
        return *this;
    }
    
    auto&& increment() && {
        i++;
       return std::move(*this);
    }
    
    这导致

    auto b2 = test_class{7}.increment();
    
    移动构造
    b2
    ,因为
    test\u class{7}
    是临时的,并且调用
    test\u class::increment
    &&
    重载

  • 对于真正的就地构造(即,甚至不是移动构造),可以将所有特殊和非特殊成员函数转换为
    constexpr
    版本

    constexpr auto b2 = test_class{7}.increment();
    
    显然,对于简单的
    test_类
    ,这是可能的,但对于不允许
    constexpr
    成员函数的更一般的场景,这是不可能的

  • 基本上,将a分配给a需要调用构造函数,即复制或移动。这与函数两边都知道是同一个不同对象的情况不同。a也可以像指针一样引用共享对象


    最简单的方法可能是完全优化复制构造函数。值设置已经由编译器优化,只有
    std::cout
    无法优化

    test_class(const test_class& t) = default;
    
    (或者只删除复制和移动构造函数)


    由于您的问题基本上与引用有关,如果您希望停止以这种方式复制,解决方案可能不会返回对对象的引用

      void increment();
    };
    
    auto b = test_class{7};//does not call copy constructor
    b.increment();//does not call copy constructor
    

    第三种方法首先依赖于复制省略-但是这需要将操作重写或封装到一个函数中,从而完全避免问题(我知道这可能不是您想要的,但可能是其他用户的解决方案):


    或者如中所示。

    编译时使用哪种优化级别?
    auto b=test_class{7};
    不调用复制构造函数,因为它实际上相当于
    test_class b{7}
    和编译器非常聪明,能够识别这种情况,因此可以轻松避免任何复制。对于
    b2
    ,则无法做到这一点。在所示的示例中,移动和复制之间可能没有任何或太大的差异,而且并非所有人都意识到这一点。如果在其中插入类似于大向量的内容,则可能会有不同nt很重要。通常情况下,移动只对使用类型的资源有意义(如使用大量堆内存等)-这里是这样吗?这个示例看起来很做作。您是否确实有I/O(
    std::cout
    )在您的复制构造函数中?如果没有它,副本应该被优化掉。@rustyx,删除std::cout并使复制构造函数显式。这表明复制省略不依赖于std::cout。第二种替代方法也使
    b2
    不可修改。@Someprogrammerdude的观点很好。我想
    continit
    将是解决此问题的方法去那里。函数名后面的“与”符号的用途是什么?我以前从未见过。@PhilipNelson它们是,并且可以指示
    这个
    常量
    成员相同functions@O“尼尔在想另一个案子,对吗
    auto b2 = []{test_class tmp{7}; tmp.increment().increment().increment(); return tmp;}(); //<-- b2 becomes 10 - copy constructor not called
    
    auto b2 = std::move(test_class{7}.increment());