为什么使用已删除的复制构造函数的emplace_back不起作用?

22
我有一个类型,我已经删除了其复制构造函数,并且我想要一个vector来存储这种类型,因此我需要通过emplace_back创建所有元素。但是,emplace_back似乎需要一个复制构造函数,因为编译器会发出有关无法实例化emplace_back的警告,因为复制构造函数已被删除。为什么它需要复制构造函数?我认为emplace_back的整个目的是在不复制任何内容的情况下构建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。


http://cpp.sh/9v5w 这里无法工作。 - Humam Helfawi
此处还有http://goo.gl/eLUPjR - Humam Helfawi
emplace_back 不需要复制构造函数,但当向量的容量不足以存储新元素时,向量需要重新分配其元素,这需要复制/移动构造函数。通过删除复制构造函数,您还可以防止它生成默认的移动构造函数。在这种情况下,声明一个移动构造函数可能会起作用。 - Danh
3个回答

34

vector的内部存储增长时,它将需要将元素从旧存储移动到新存储。通过删除复制构造函数,您还可以防止生成默认的移动构造函数。


12

要能够调用emplace_back,您的类型应该是EmplaceConstructibleMoveInsertible

如果您已删除了复制构造函数,则需要为您的类提供移动构造函数。(请查看此处了解emplace_back的要求)

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

2
如果您尝试运行此代码:

// 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);
}

你将得到以下结果:

由数组构造

演示现场

很明显,只调用了来自std::Array的构造函数。所以,不需要复制构造函数。但是,同时如果你删除了复制构造函数,编译器会报错(至少在我尝试过的两个编译器上firstsecond)。我认为有些编译器在使用emplace_back时会检查复制构造函数的存在,即使在这种实际情况下并不必要,而其他编译器则不会。我不知道这里的标准是什么(哪个编译器是正确的或错误的)。

1
问题在于 emplace_back 可能会导致向量增长,这需要内部的对象可移动。由于 MyType 具有用户声明的复制构造函数,因此不会生成移动构造函数,该类既不可复制也不可移动。 - Angew is no longer proud of SO
1
但至少在这种情况下没有调用复制或移动操作,那么有什么区别呢? - Humam Helfawi
@HumamHelfawi 这可能最终是必需的。这意味着有一些代码将在那里处理该情况。为此,移动构造函数和复制构造函数必须在编译时存在。 - bashrc
区别在于 emplace_back 的代码包含对移动构造函数的调用。在运行时,控制权不会通过它,但它必须能够编译。 - Angew is no longer proud of SO

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接