23

我有一个类,其复制构造函数被显式删除(因为 A 在内部使用指针,我不想陷入浅拷贝陷阱):

class A {
  public:
    A(const A&) = delete;
    A& operator=(const A&) = delete;

    A(const B& b, const C& c);
}

现在我有一个类型的向量,vector<A> aVector;我想在其中插入元素 - 所以我使用emplace_back

aVector.emplace_back(b, c);

但是,这无法使用 gcc 进行编译,并且出现错误 -

third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...)
third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/stl_uninitialized.h:77:3:   required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator)  
third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/stl_uninitialized.h:119:41:   required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) 
third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/stl_uninitialized.h:260:63:   required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) 
third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/stl_uninitialized.h:283:67:   required from '_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&)
third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/vector.tcc:410:6:   required from 'void std::vector<_Tp, _Alloc>::_M_emplace_back_aux(_Args&& ...) 
third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/vector.tcc:102:4:   required from 'void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...)

这个错误的原因是什么?如何在不删除复制构造函数的情况下修复它?我需要一个移动构造函数 - 是否需要显式定义?

4

4 回答 4

24

您应该添加移动构造函数 - 因为std::vector::emplace_back可能会进行需要复制/移动构造函数的重定位。或者只是使用std::deque.

现场演示

#include <vector>
#include <deque>
using namespace std;

struct NoCopyNoMove
{
    NoCopyNoMove(const NoCopyNoMove&) = delete;
    NoCopyNoMove& operator=(const NoCopyNoMove&) = delete;
    NoCopyNoMove(NoCopyNoMove&&) = delete;
    NoCopyNoMove& operator=(NoCopyNoMove&&) = delete;

    NoCopyNoMove(int){};
};

struct OnlyMove
{
    OnlyMove(const OnlyMove&) = delete;
    OnlyMove& operator=(const OnlyMove&) = delete;
    OnlyMove(OnlyMove&&) noexcept {}
    OnlyMove& operator=(OnlyMove&&) noexcept {}

    OnlyMove(int){};
};

int main()
{
    deque<NoCopyNoMove> x;
    x.emplace_back(1);

    vector<OnlyMove> y;
    y.emplace_back(1);
}

§ 23.2.3 表 101——可选的序列容器操作

a.emplace_back(args)[...]

要求T应从argsEmplaceConstructible进入。XvectorT亦须MoveInsertableX

于 2013-11-07T02:02:35.837 回答
12

该错误不是 emplace_back 的错。要将对象放入向量中,它必须是可移动的或可复制的。如果您实际运行代码并实现了复制构造函数,您会注意到它永远不会被调用。这是 cppreference.com 上的一个条目
在此处输入图像描述

我要解决这个问题是实现移动构造函数,使其编译,我看不出拥有移动构造函数有任何真正的缺点。与 cctor 一样,移动构造函数不会在您当前的代码中被调用。

于 2013-11-07T02:00:08.003 回答
1

只想添加到@kayleeFrye_onDeck 的答案。我的情况与他们的情况几乎相同,适用于我的确切语法(基于评论中的反馈)如下:

vector< std::unique_ptr<ClassName> > names; // Declare vector of unique_ptrs of the class instance

std::unique_ptr<ClassName> name_ptr = std::make_unique<ClassName>();
names.push_back(std::move(name_ptr)); // Need to use std::move()

// Now you can access names objects without error:
names[0]->classMethod();
于 2019-08-06T21:33:33.440 回答
0

我在外部库的类中遇到了这个问题。我得到了,

"Error C2280 ClassName::ClassName(const ClassName &)': attempting to reference a deleted function"

我猜我使用的类已经删除了它的复制构造函数。我无法将它添加到std我所知道的自定义派生类对象的任何容器中,这些容器用我的一些助手包装了它们的对象,以帮助进行初始化/错误检查。

我用(有风险的)指针解决了这个阻止程序。

基本上,我过渡到了这个:

std::vector<ClassName*> names;
ClassName name("arg");
ClassName name_ptr = &name;
names.push_back(name_ptr);

由此,最初:

std::vector<ClassName> names;
ClassName name("arg");
names.push_back(name);

有趣的是,这是我第一次使用 C++ 编码,由于没有已知的替代方案,我实际上需要使用指针来满足非指针特定的使用要求。这让我担心我可能会错过自己代码中的一些基本内容。

也许有更好的方法可以做到这一点,但它还没有出现在这个问题的答案列表中......

编辑警告:

我应该在之前提到这一点,谢谢aschepler;如果你这样做并且你使用的容器比对象寿命长,“砰,你死了。”

于 2017-07-14T02:27:06.903 回答