Я ищу 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
?). Честно говоря, я не знаю, что происходит, может ли кто-нибудь объяснить?
Это называется [оптимизация возвращаемого значения] (https://en.wikipedia.org/wiki/Return_value_optimization). Если вы используете gcc try для компиляции с помощью переключателя '-fno-elide-constructors', чтобы исключить возможность копирования. – Praetorian
Хорошо, и это RVO работает всегда? Независимо от сложности (в коде) функции '' get_object() ''? – Robin92
Нет, нет никакой гарантии, что это всегда произойдет, но это очень распространенная техника оптимизации, и, вероятно, будет сложно предотвратить компилятор от этого не делать по умолчанию. Кроме того, как упоминалось на странице Википедии *, реализация может опустить операцию копирования, вызванную оператором return, даже если конструктор копирования имеет побочные эффекты *. Таким образом, код внутри конструктора копирования не имеет значения. Что касается функции 'get_object()', если у вас несколько операторов return, и, возможно, они не все возвращают один и тот же тип (но типы конвертируются в 'Object'), вы можете предотвратить RVO, но это сомнительно – Praetorian