C ++ 11移动构造函数未调用,默认构造函数首选 [英] C++11 move constructor not called, default constructor preferred

查看:170
本文介绍了C ++ 11移动构造函数未调用,默认构造函数首选的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有这个类:

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("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

我使用VS2010的默认设置。我希望最后一个对象( z )是移动构造的,但它不是!如果我使用 X z(move(X(test))); 那么输出的最后一行是 ctor move test ,正如我所料。是否是(N)RVO的情况?

I am using VS2010 with default settings. I'd expect the last object (z) to be move-constructed, but it's not! If I use X z( move(X("test")) ); then the last lines of the output are ctor move test, as I'd expect. Is it a case of (N)RVO?

Q :应该根据标准调用move-ctor吗?

Q: Should the move-ctor be called according to the standard? If so, why isn't it called?

推荐答案

你看到的是

What you are seeing is copy elision, which allows the compiler to directly construct a temporary into a target it is to be copied/moved into and thus elide a copy (or move) constructor/destructor pair. The situations in which the compiler is allowed to apply copy elision are specified in §12.8.32 of the C++11 standard:


当满足某些标准,即使对象的复制/移动
构造函数和/或析构函数具有副作用,也允许实现忽略
类对象的复制/移动构造。在这样的
情况下,实现将省略的
复制/移动操作的源和目标视为仅仅参考
相同对象的两种不同方法,并且该对象的销毁发生在后面的
的时候,两个对象将被销毁没有
优化。在以下
情况下允许复制/移动
操作(称为复制精确):

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization. This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which maybe combined to eliminate multiple copies):


  • 在具有类返回类型的函数中的返回语句中,当表达式是具有

    的非易失性自动对象的名称时,相同的cv不限定类型为函数返回类型,通过将自动

    对象直接构造到函数的返回值中,可以省略

    复制/移动操作

  • throw-expression,当操作数是其范围不超过
    的非易失性自动对象的名称时,最内层的try-block结束(如果有的话),
    copy /将操作数从操作数移动到异常对象(15.1)
    可以通过将自动对象直接构造为
    异常对象

  • 没有被绑定到一个引用(12.2)将被复制/移动到一个类对象与
    相同的cv无限制类型,复制/移动操作可以通过
    省略直接构造临时对象当异常处理程序的异常声明(第15条)声明一个相同类型的对象时(除了cv),

    省略复制/移动

  • < -quali fi cation)as

    异常对象(15.1),可以省略复制/移动操作

    将异常声明作为异常的别名

    对象,除非
    执行由

    声明的对象的构造函数和析构函数,否则程序的含义将保持不变。
  • in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object with
    the same cv-unqualified type as the function return type, the
    copy/move operation can be omitted by constructing the automatic
    object directly into the function’s return value
  • in a throw-expression, when the operand is the name of a non-volatile automatic object whose scope does not extend beyond the end of the innermost enclosing try-block (if there is one), the copy/move operation from the operand to the exception object (15.1) can be omitted by constructing the automatic object directly into the exception object
  • when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with he same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the
    omitted copy/move
  • when the exception-declaration of an exception handler (Clause 15) declares an object of the same type (except for cv-qualification) as
    the exception object (15.1), the copy/move operation can be omitted
    bytreatingthe exception-declaration as an alias for the exception
    object if the meaning of the program will be unchanged except for the execution of constructors and destructors for the object declared by
    the exception-declaration.

这篇关于C ++ 11移动构造函数未调用,默认构造函数首选的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆