C++ C++;11未调用移动构造函数,首选默认构造函数

C++ C++;11未调用移动构造函数,首选默认构造函数,c++,c++11,move-semantics,C++,C++11,Move Semantics,假设我们有这个类: class X { public: explicit X (char* c) { cout<<"ctor"<<endl; init(c); }; X (X& lv) { cout<<"copy"<<endl; init(lv.c_); }; X (X&& rv) { cout<<"move"<<endl; c_ = rv.c_; rv.c_ = nul

假设我们有这个类:

class X {
public:
    explicit X (char* c) { cout<<"ctor"<<endl; init(c); };
    X (X& lv)  { cout<<"copy"<<endl;  init(lv.c_); };
    X (X&& rv) { cout<<"move"<<endl;  c_ = rv.c_; rv.c_ = nullptr; };

    const char* c() { return c_; };

private:
    void init(char *c) { c_ = new char[strlen(c)+1]; strcpy(c_, c); };
    char* c_;

};
X类{
公众:
显式X(char*c){cout您看到的是,它允许编译器直接将一个临时对象构造到要复制/移动到的目标中,从而省略一个复制(或移动)构造函数/析构函数对。允许编译器应用复制省略的情况在c++11标准的§12.8.32中规定:

当满足某些条件时,允许实现省略 类对象的复制/移动构造,即使复制/移动 在这种情况下,对象的构造函数和/或析构函数具有副作用 在某些情况下,实现将处理省略的源和目标 复制/移动操作只是引用 同一个对象,该对象的销毁发生在 这两个物体在没有 优化。这省略了复制/移动 在以下情况下,允许执行名为复制省略的操作 情况(可能结合使用以消除多个副本):

  • 在具有类返回类型的函数中的return语句中,当表达式是具有
    与函数返回类型相同的cv不合格类型,
    复制/移动操作可以通过构造自动 对象直接输入函数的返回值
  • 在抛出表达式中,当操作数是作用域未超出范围的非易失性自动对象的名称时 最里面的封闭try块(如果有)的结尾 从操作数到异常对象的复制/移动操作(15.1) 可以通过将自动对象直接构造到 异常对象
  • 当未绑定到引用(12.2)的临时类对象将被复制/移动到类对象时 相同的cv不合格类型,复制/移动操作可以通过 将临时对象直接构建到目标中
    省略复制/移动
  • 当异常处理程序(第15条)的异常声明声明与
    对于异常对象(15.1),可以省略复制/移动操作
    将异常声明作为异常的别名处理
    对象,除非 执行由声明的对象的构造函数和析构函数
    异常声明

您正在显式调用
X的
char*
constructor
X(“test”)


因此,它正在打印
ctor

您在第三行代码中得到的
ctor
输出用于构造临时对象。之后,确实,临时对象被移动到新变量
z
中。在这种情况下,编译器可能会选择省略复制/移动,看起来它就是这样做的

该标准规定:

(§12.8/31)当满足某些标准时,允许实现忽略类对象的复制/移动构造,即使对象的复制/移动构造函数和/或析构函数具有副作用。[…]在以下情况下,允许省略复制/移动操作,称为复制省略(可以合并以消除多个副本):
[…]
-当未绑定到引用(12.2)的临时类对象将被复制/移动到具有相同cv不合格类型的类对象时,可以通过将临时对象直接构造到省略的复制/移动目标中来省略复制/移动操作
[……]

一个重要的条件是源对象和目标对象的类型相同(除了cv限定,即
const

因此,强制调用move构造函数的一种方法是将对象初始化与隐式类型转换结合起来:

#包括
结构B
{};
结构A
{
A(){}
A(A&&A){

std::难道这是复制省略。如果复制省略失败,就会发生移动。为什么你的帖子标题说“首选默认构造函数”?没有调用默认构造函数,也没有首选的构造函数来代替移动构造函数。它将被完全删除。此代码自C++11以来将无法编译;字符串文本不能隐式转换为非常量
char*
。如果使用g++则可能重复传递标志
-fno elide constr构造函数
,这将关闭复制省略,将调用移动构造函数,然后在声明
z
时调用
X
的移动构造函数。能否提供一个不使用
std::move
的简单示例,强制编译器使用移动构造函数?@elmes:为什么要调用移动构造函数,当不需要这样做时?@elmes:
xz((rand()%2)?X(“test”):X(“test”);
@Grizzly:C++11要求当可以进行复制省略(从函数返回相同类型的对象)时,每个
返回本地变量;
都会首先尝试移动
本地变量
。不需要显式移动,这会妨碍(N)RVO@Xeo:我不明白。即使在所描述的情况下,标准也可能允许复制省略,但是编译器是否能够做到这一点(特别是在生命周期重叠的情况下)值得怀疑。我在哪里说过在返回局部变量时需要显式移动(或不可移动)?can
a::a(B&&B)
是否被视为移动构造函数?N3936草案(12.8.3)说:“如果类X的非模板构造函数的第一个参数是类型X&&、常量X&&、volatile X&&,或const volatile X&&&,并且
X x("test");
cout << x.c() << endl;
X y(x);
cout << y.c() << endl;
X z( X("test") );
cout << z.c() << endl;
ctor
test
copy
test
ctor   <-- why not move?
test
#include <iostream>

struct B
{};

struct A
{
  A() {}
  A(A&& a) {
    std::cout << "move" << std::endl;
  }
  A(B&& b) {
    std::cout << "move from B" << std::endl;
  }
};


int main()
{
  A a1 = A(); // move elided
  A a2 = B(); // move not elided because of type conversion
  return 0;
}