Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.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++ 存在RVO时默认/删除移动构造函数和赋值_C++_C++11_Return Value_Rvalue Reference_Return Value Optimization - Fatal编程技术网

C++ 存在RVO时默认/删除移动构造函数和赋值

C++ 存在RVO时默认/删除移动构造函数和赋值,c++,c++11,return-value,rvalue-reference,return-value-optimization,C++,C++11,Return Value,Rvalue Reference,Return Value Optimization,我想这个问题已经被问过了,但我还没有找到类似的答案 让我们看一个人为的例子 #include <iostream> #include <string> #include <cassert> #define LOG \ std::cout << __PRETTY_FUNCTION__ << ' ' << str_ << '\t' << this << std::endl; c

我想这个问题已经被问过了,但我还没有找到类似的答案

让我们看一个人为的例子

#include <iostream>
#include <string>
#include <cassert>

#define LOG \
  std::cout << __PRETTY_FUNCTION__ << ' ' << str_ << '\t' << this << std::endl;

    class Test {
     public:
      Test(std::string const &str) : str_(str) { LOG; }
      Test(Test const &rhs) : str_(rhs.str_) { LOG; }
      // Test(Test &&rhs) = delete;
      Test(Test &&rhs) : str_(std::move(rhs.str_)) { LOG; }
      // Test &operator=(Test const &rhs) {
      // if (this == &rhs) return this;
      //   str_ = rhs.str_;
      //   LOG;
      //   return *this;
      // }
      // Test &operator=(Test &&rhs) = delete;
      // Test &operator=(Test &&rhs) {
      //   assert(this != &rhs);
      //   str_.swap(rhs.str_);
      //   LOG;
      //   return *this;
      // }
      ~Test() { LOG; }
      static Test gen() {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
        return Test("DUMMY");
      }

     private:
      std::string str_;
    };

    int main(void) {
      {
        Test test = Test("test");
        Test t(test);
      }
      std::cout << std::endl;
      { Test t0(Test("t0")); }
      std::cout << std::endl;
      {
        Test t1 = Test{"t1"};
        /// t1 = Test("t2");
      }
      std::cout << std::endl;
      { Test t(Test::gen()); }
      return 0;
    }
当我像src中那样定制move构造函数时,它会编译。然而 但是,甚至没有调用移动构造函数(结果如下):

后来我发现它可能是由于
返回值优化
造成的,所以我用
-fno-elide构造函数重新编译了它。这一次的结果如下:

Test::Test(const std::string &) test    0x7fff9590cd90
Test::Test(Test &&) test    0x7fff9590cd98
Test::~Test()   0x7fff9590cd90
Test::Test(const Test &) test   0x7fff9590cd78
Test::~Test() test  0x7fff9590cd78
Test::~Test() test  0x7fff9590cd98

Test::Test(const std::string &) t0  0x7fff9590cd68
Test::Test(Test &&) t0  0x7fff9590cd70
Test::~Test()   0x7fff9590cd68
Test::~Test() t0    0x7fff9590cd70

Test::Test(const std::string &) t1  0x7fff9590cd48
Test::Test(Test &&) t1  0x7fff9590cd50
Test::~Test()   0x7fff9590cd48
Test::~Test() t1    0x7fff9590cd50

static Test Test::gen()
Test::Test(const std::string &) DUMMY   0x7fff9590ccf0
Test::Test(Test &&) DUMMY   0x7fff9590cd28
Test::~Test()   0x7fff9590ccf0
Test::Test(Test &&) DUMMY   0x7fff9590cd30
Test::~Test()   0x7fff9590cd28
Test::~Test() DUMMY 0x7fff9590cd30
它按预期调用了
移动构造函数。但是,显式删除
move构造函数仍然会导致程序无法编译

我的问题是:
  • 当删除
    移动构造函数时,为什么会报告错误为什么它没有匹配
    复制构造函数
    (虽然没有与
    移动构造函数
    完全匹配)?
    C++03
    没有右值参考,那么编译器的解决方案是什么?此外,我阅读并假设,在我的例子中,由于我指定了一个用户声明的复制构造函数,所以移动构造函数不应该是默认的(因此它应该被删除?),我也意识到有类似的描述。叮当声符合标准吗

  • 返回值优化在这里做了什么?特别是,为什么调用
    Test::Test(const Test&)
    而不是
    Test::Test(Test&)
    ?(很抱歉,我没有注意到RVO版本结果中只有一个副本构造函数调用)

  • 我还注意到
    移动分配
    中存在类似问题(如果删除,则编译投诉错误)。这是怎么回事

  • 即使编译器省略了复制或移动,该语言仍然要求函数存在并可访问。这是为了使程序始终一致地编译,而不管编译器是否删除特定的复制/移动

  • test
    有一个名称,因此它会自动成为左值,如果没有显式的
    std::move
    ,就不能从中移动。因此,编译器必须将
    test
    复制到
    t

  • 我不明白您期望发生什么-我看不出它为什么不调用移动分配操作符


  • 简短的版本是,如果在优化之前名义上调用了move或copy构造函数,那么它们必须存在并且可以访问。这正是语言标准的要求。

    删除的特殊成员函数参与重载解析,并且需要移动或复制构造函数,即使RVO省略了副本。如果提供了复制构造函数但没有移动构造函数,则不会删除移动构造函数。它根本没有声明。无论是否执行了优化,在没有进行优化的情况下,程序都必须有效。@HongxuChen:不,不能调用既不存在也不被称为存在的函数。@HongxuChen:不,代码中从来没有提到过未声明的函数,它以任何方式、形状或形式都不存在,时期它不存在。
    deleted
    函数“存在”,但在您尝试使用它时会报告错误。(你是对的,它非常奇怪和愚蠢,我认为
    已删除
    的名称很糟糕。)1。我在理解标准中的
    move构造函数
    implicit rule`时仍然有问题。是否会为RVO版本生成此默认移动构造函数?2。只需删除问题的第二部分。对不起,我弄错了。这种情况类似于构造函数,当删除
    move-assignment
    时,编译器会发出错误。基本上我不知道为什么
    move-constructor/assignment
    应该存在,即使最后没有调用它们?确切地说,move-constructor何时将从生成的类中删除?
    Test::Test(const std::string &) test    0x7fff2e513448
    Test::Test(const Test &) test   0x7fff2e513430
    Test::~Test() test  0x7fff2e513430
    Test::~Test() test  0x7fff2e513448
    
    Test::Test(const std::string &) t0  0x7fff2e513428
    Test::~Test() t0    0x7fff2e513428
    
    Test::Test(const std::string &) t1  0x7fff2e513410
    Test::~Test() t1    0x7fff2e513410
    
    static Test Test::gen()
    Test::Test(const std::string &) DUMMY   0x7fff2e5133f8
    Test::~Test() DUMMY 0x7fff2e5133f8
    
    Test::Test(const std::string &) test    0x7fff9590cd90
    Test::Test(Test &&) test    0x7fff9590cd98
    Test::~Test()   0x7fff9590cd90
    Test::Test(const Test &) test   0x7fff9590cd78
    Test::~Test() test  0x7fff9590cd78
    Test::~Test() test  0x7fff9590cd98
    
    Test::Test(const std::string &) t0  0x7fff9590cd68
    Test::Test(Test &&) t0  0x7fff9590cd70
    Test::~Test()   0x7fff9590cd68
    Test::~Test() t0    0x7fff9590cd70
    
    Test::Test(const std::string &) t1  0x7fff9590cd48
    Test::Test(Test &&) t1  0x7fff9590cd50
    Test::~Test()   0x7fff9590cd48
    Test::~Test() t1    0x7fff9590cd50
    
    static Test Test::gen()
    Test::Test(const std::string &) DUMMY   0x7fff9590ccf0
    Test::Test(Test &&) DUMMY   0x7fff9590cd28
    Test::~Test()   0x7fff9590ccf0
    Test::Test(Test &&) DUMMY   0x7fff9590cd30
    Test::~Test()   0x7fff9590cd28
    Test::~Test() DUMMY 0x7fff9590cd30