【问题标题】:Why doesn't this use of emplace_back with deleted copy constructor work?为什么将 emplace_back 与已删除的复制构造函数一起使用不起作用?
【发布时间】:2016-04-05 06:32:57
【问题描述】:

我有一个类型,我已经从中删除了复制构造函数,并且我想要一个这种类型的vector,所以我需要通过emplace_back 创建所有元素。但是,emplace_back 似乎需要复制构造函数,因为编译器会发出警告,指出由于复制构造函数已被删除,因此无法实例化 emplace_back。为什么需要复制构造函数?我认为emplace_back 的全部意义在于在不复制任何内容的情况下构建vector。我什至可以拥有一个没有复制构造函数的对象的vector 吗?

class MyType {
public:
    MyType(std::array<double, 6> a) {}
    MyType(const MyType& that) = delete;
};

int main() {
    std::vector<MyType> v;
    std::array<double, 6> a = {1,2,3,4,5,6};
    v.emplace_back(a);
}

编译器是clang/llvm。

【问题讨论】:

  • cpp.sh/9v5w 这里不起作用
  • 这里还有goo.gl/eLUPjR
  • emplace_back 不需要复制构造函数,但是当vector的容量不足以存储新元素时,vector需要重新分配其元素,这需要复制/移动构造函数。通过删除复制构造函数,您还可以防止它生成默认的移动构造函数。在这种情况下,声明一个移动构造函数可能会起作用

标签: c++ constructor stdvector emplace


【解决方案1】:

vector 的内部存储增长时,它需要将元素从旧存储移动到新存储。 By deleting the copy constructor, you also prevent it generating the default move constructor.

【讨论】:

    【解决方案2】:

    为了能够调用 emplace_back,您的类型应该是 EmplaceConstructibleMoveInsertible 。 如果您删除了复制构造函数,则需要为您的类提供移动构造函数。 (查看this 了解emplace_back 的要求)

     MyType(MyType &&a) {/*code*/} //move constructor
    

    【讨论】:

      【解决方案3】:

      如果您尝试运行此代码:

      // Example program
      #include <iostream>
      #include <string>
      #include <array>
      #include <vector>
      class MyType {
      public:
          MyType(std::array<double, 6> a) {
              std::cout<< "constructed from array\n";
              }
          MyType(const MyType& that){
                std::cout<< "copy\n";
          }
      
          MyType(MyType&& that){
                std::cout<< "move\n";
          }
      };
      
      int main() {
          std::vector<MyType> v;
          std::array<double, 6> a = {1,2,3,4,5,6};
          v.emplace_back(a);
      }
      

      你会得到以下结果:

      从数组构造

      Live Demo

      很明显,只调用了来自std::Arrayconstructor。所以,不需要copy constructor。但同时如果你deletedcopy constructor,编译器会报错(至少在我试过的两个编译器上firstsecond)。我认为一些编译器会在使用 emplace_back 时检查copy constructor 的存在,即使在这种实际情况下没有必要,而其他编译器则不需要。我不知道这里的标准是什么(哪个编译器是对还是错)。

      【讨论】:

      • 问题是emplace_back会导致vector变大,这就需要里面的对象是可以移动的。并且由于MyType 有一个用户声明的复制构造函数,因此不会生成移动构造函数,并且该类既不可复制也不可移动。
      • 但至少在这种情况下没有调用复制或移动.. 那么有什么区别?
      • @HumamHelfawi 最终可能需要。这意味着有一些代码可以处理这种情况。为此,移动构造函数和复制构造函数必须在编译时存在。
      • 不同之处在于emplace_back 的代码包含对移动ctor 的调用。控制在运行时不会通过它,但无论如何它必须是可编译的。
      猜你喜欢
      • 1970-01-01
      • 2013-08-24
      • 2015-11-02
      • 1970-01-01
      • 2023-03-17
      • 2018-07-17
      • 2020-10-03
      • 2018-09-17
      • 1970-01-01
      相关资源
      最近更新 更多