【问题标题】:Not expected constructor called未调用的构造函数
【发布时间】:2013-08-12 18:34:00
【问题描述】:

我正在研究 C++11 移动构造函数,但有些东西不起作用。事实上,这个问题甚至在我开始编写这样的构造函数之前就已经存在。这是一段代码:

#include <iostream>
#include <string>
#include <sstream>

class Object {
    static std::ostream& log(Object &obj) {
        std::cout << "Object::id = " << obj.mId << "::"; 
        return std::cout;
    }

    unsigned mId = 0;
    std::string *mText = nullptr;

    unsigned nextUniqueId() const {
        static unsigned id = 0;
        return ++id;
    }

    const std::string textInfo() const {
        std::ostringstream oss;
        oss << "mText @ " << &mText;
        if (mText) oss << " = " << *mText;

        return oss.str();
    }

public:
    Object() = delete;
    Object& operator= (const Object&) = delete;

    explicit Object(const std::string& str) : mId(this->nextUniqueId()), mText(new std::string(str)) {
        Object::log(*this) << "constructor::one-argument\n";
    }

    Object(const Object& obj) : mId(this->nextUniqueId()), mText(new std::string(*obj.mText)) {
        Object::log(*this) << "constructor::copy\n";
    }

    virtual ~Object() {
        Object::log(*this) << "destructor::" << this->textInfo() << "\n";
        if (mText) {
            delete mText;
            mText = nullptr;
        }
    }
};

static Object get_object() {
    return Object("random text");
}

int main(int argc, char **argv) {
    Object a("first object");  // OK

    /*
     * Expected behaviour: inside get_object() function new Object is created which is then   copied into
     * variable b. So that new ID should be given.
     */
    Object b = get_object();  // What the hell?! Not what expected! Why?

    std::cout << std::endl;
    return 0;
}

预期的输出与此类似:

Object::id = 1::constructor::one-argument    
Object::id = 2::constructor::one-argument
Object::id = 2::destructor::mText @ 0x7fff32c25f70 = random text
Object::id = 3::constructor::copy

Object::id = 3::destructor::mText @ <DIFFERENT THAN IN ID=2> = random text
Object::id = 1::destructor::mText @ 0x7fff32c25f90 = first object

我得到了这个:

Object::id = 1::constructor::one-argument
Object::id = 2::constructor::one-argument

Object::id = 2::destructor::mText @ 0x7fff32c25f70 = random text
Object::id = 1::destructor::mText @ 0x7fff32c25f90 = first object

看起来像变量b 是在现场创建的(可能类似于inline?)。老实说我不知道​​是怎么回事,谁能解释一下?

【问题讨论】:

  • 它叫做return value optimization。如果您使用 gcc,请尝试使用 -fno-elide-constructors 开关进行编译,以防止发生复制省略。
  • 好的,这个 RVO 总是有效吗?不管get_object() 函数的复杂性(在代码中)如何?
  • 不,不能保证它总是会发生,但它是一种非常常见的优化技术,可能很难阻止编译器默认不这样做。此外,正如 Wikipedia 页面上所述,即使复制构造函数有副作用,实现也可以省略由 return 语句产生的复制操作。所以复制构造函数中的代码无关紧要。至于get_object() 函数,如果你有几个return 语句,并且可能它们不都返回相同的类型(但类型可以转换为Object),你可能会阻止RVO,但这是值得怀疑的

标签: c++ class c++11 constructor


【解决方案1】:

编译器优化了复制/移动就是...

【讨论】:

    【解决方案2】:

    这称为返回值优化或 RVO。编译器选择直接在mainb 的内存位置创建由get_object() 返回的临时值。它得到了标准的认可,并且是一种非常常见的优化。

    【讨论】:

      【解决方案3】:

      允许编译器应用“返回值优化”RVO,这就是优化副本的原因。请注意,尽管与输出消息相关的副作用,标准仍允许这样做

      【讨论】:

        猜你喜欢
        • 2016-08-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-13
        • 2015-06-27
        • 2011-10-18
        • 2015-10-09
        • 1970-01-01
        相关资源
        最近更新 更多