C++ 如何在不调用复制构造函数的情况下向向量添加元素?

C++ 如何在不调用复制构造函数的情况下向向量添加元素?,c++,c++11,vector,copy-constructor,move-semantics,C++,C++11,Vector,Copy Constructor,Move Semantics,由于某些原因,我的临时本地对象在添加到向量时总是复制构造/销毁,这会导致嵌套的std::reference_wrapper出现问题,因为之后的复制构造和销毁导致这些问题变得无效(std::reference_wrapper目标位于被销毁的对象内部->因此,如果源对象被销毁,它们在复制构造的对象中无效)但是如果可能的话,我想完全避免额外的复制/销毁-这似乎是不可能的,因为无论我尝试什么,它总是想调用复制构造函数(甚至使用std::vector::emplace_back) 考虑到这个简单的例子(为

由于某些原因,我的临时本地对象在添加到向量时总是复制构造/销毁,这会导致嵌套的
std::reference_wrapper
出现问题,因为之后的复制构造和销毁导致这些问题变得无效(
std::reference_wrapper
目标位于被销毁的对象内部->因此,如果源对象被销毁,它们在复制构造的对象中无效)但是如果可能的话,我想完全避免额外的复制/销毁-这似乎是不可能的,因为无论我尝试什么,它总是想调用复制构造函数(甚至使用
std::vector::emplace_back

考虑到这个简单的例子(为了不涉及
std::reference\u wrapper
而更容易理解),它总是试图调用复制构造函数——我不明白为什么

#include <vector>

class A{
public:
  A(int a) : a(a){ }
  int getInt() const{ return a; }
  A(const A&) = delete; /* to deny copy-construction */
private:
  int a;
};

int main(int argc, char* argv[]){
  std::vector<A> vec;
  vec.emplace_back(3);              /* tries to call copy constructor */
  vec.push_back(A(3));              /* tries to call copy constructor */
  vec.push_back(std::move(A(3)));   /* tries to call copy constructor */
  return 0;
}
#包括
甲级{
公众:
A(inta):A(A){}
int getInt()常量{返回a;}
A(const A&)=delete;/*拒绝复制构造*/
私人:
INTA;
};
int main(int argc,char*argv[]){
std::vec;
vec.emplace_back(3);/*尝试调用复制构造函数*/
vec.push_back(A(3));/*尝试调用复制构造函数*/
vec.push_back(std::move(A(3));/*尝试调用复制构造函数*/
返回0;
}

你知道我在这里遗漏了什么吗?

根据Visual Studio 2013,强调我的:

“rValueVo.V3.0”在“条件”下添加新规则到“强>自动生成移动构造函数和移动赋值运算符>,但是>在Visual Studio 2013 中,由于时间和资源限制,在Visual C++中没有实现。

Visual Studio 2013指定为使用右值引用v2.1

注意:作为注释中的注释,在您的示例中显式禁用复制构造函数也存在问题。根据

如果没有为类类型(struct、class或union)提供用户定义的移动构造函数,并且以下所有情况均为真:

  • 没有用户声明的副本构造函数
  • 没有用户声明的复制分配运算符
  • 没有用户声明的移动分配运算符
  • 没有用户声明的析构函数
  • (直到C++14)隐式声明的move构造函数没有定义为deleted,这是由于下一节将详细介绍的条件
然后编译器将声明一个move构造函数作为其类的内联公共成员,签名为T::T(T&&)

一个类可以有多个移动构造函数,例如T::T(const T&&)和T::T(T&&)。如果存在一些用户定义的移动构造函数,用户仍然可以使用关键字default强制生成隐式声明的移动构造函数

这意味着您的示例代码还阻止自动生成移动构造函数(即,它有一个用户声明的复制构造函数)

您需要显式声明移动构造函数和/或移动赋值运算符

class A
{
public:
    A(int a) : a(a) {}

    A(const A&) = delete;

    A(A&& other) : a(other.a) {}

    int getInt() const { return a; }

private:
    int a;
};

int main(int argc, char* argv[])
{
    std::vector<A> vec;
    vec.emplace_back(3);
    vec.push_back(A(3));
    vec.push_back(std::move(A(3)));

    return 0;
}
A类
{
公众:
A(inta):A(A){}
A(常数A&)=删除;
A(A&&other):A(other.A){}
int getInt()常量{返回a;}
私人:
INTA;
};
int main(int argc,char*argv[])
{
std::vec;
向量后置(3);
向量推回(A(3));
向量推回(标准::移动(A(3));
返回0;
}

a)前两次尝试:为什么不应该?b) 关于std::move部分,您缺少一个move构造函数(即r-value引用参数)。您使用的编译器是什么?如果移动构造函数不是自动生成的,那么您永远也不会希望调用移动构造函数。此外,对于C++ 11,如果您想禁用复制,则应该考虑使用<代码> A(const a &)=删除< /Cord>。我使用MS VisualStudio 2013。感谢
A(const A&)=delete
的建议。读取时,存储的类型必须声明placement new可以像
:new((void*)p)T(rv)
,如果没有移动构造函数,它将调用移动构造函数或复制构造函数。听起来你的类包含一个自引用。对于这种情况,您必须编写自己的复制/移动构造函数以获得适当的语义。大多数
vector
操作要求对象至少是可移动的。完全禁用复制/移动对您没有多大帮助。在这种情况下,VS2013的特性无关紧要。该类有一个用户声明的复制构造函数,因此即使在符合条件的编译器中,它也不会得到隐式声明的移动构造函数。@t.C.显式声明复制操作会禁用移动操作的自动生成,这是正确的。我只是假设人为的示例只是显式禁用复制构造函数以验证代码是否仍然有效(即,是否依赖于移动操作)。@T.C.假设这是一个列表而不是一个向量(因此不会进行内部缓冲区加倍),您的观点是否仍然有效?为什么不使用placement new?@JamesAdkison您的假设是正确的-我刚刚明确禁用了复制构造函数以进行验证