Robin92
Robin92

Reputation: 561

Not expected constructor called

I'm looking into C++11 move constructors but something doesn't work. In fact the issue is even before I started writing such a constructor. Here's a code snipped:

#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;
}

The expected output is similiar to this:

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

I get this instead:

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

which looks like variable b is created on spot (something like inline maybe?). Frankly speaking I don't know what's going on, can anyone explain?

Upvotes: 1

Views: 109

Answers (3)

That is called return value optimization or RVO. The compiler opted to create the temporary returned by get_object() directly in the memory location of b in main. It is sanctioned by the standard and a very common optimization.

Upvotes: 3

a.lasram
a.lasram

Reputation: 4411

The compiler is allowed to apply "return value optimization" RVO and that's why the copy is optimized out. Note that the standard allows this despite the side effects related to the output message

Upvotes: 1

mark
mark

Reputation: 5459

The compiler optimized out the copy/move is all...

Upvotes: 3

Related Questions