Я подозреваю, что не понимаю кое-что о семантике перемещения. Учитывая следующий код, я ожидал бы, что отладчик (MSVC2010SP1) будет вызывать членов Proxy в следующем порядке:
Proxy(Resource*)
строительство временного в getProxy
Proxy(Proxy&& other)
двигать конструирование p
~Proxy()
разрушая пустую оболочку временного, который получил его кишки, взятые ходом~Proxy() p
выходит за рамки
class Resource
{
void open(){}
public:
void close(){}
Proxy && getProxy();
};
class Proxy
{
Resource *pResource_;
Proxy(const Proxy& other); //disabled
Proxy& operator=(const Proxy& other); //disabled
public:
Proxy(Resource *pResource):pResource_(pResource){}
Proxy(Proxy&& other):pResource_(other.pResource_){other.pResource_ = nullptr;}
~Proxy()
{
if(pResource_)
pResource_->close();
pResource_ = nullptr;
}
};
Proxy && Resource::getProxy()
{
open();
return Proxy(this);
}
//somewhere else, lets say in main()
Resource r;
{
auto p = r.getProxy();
} // p goes out of scope
Вместо этого порядок:
Proxy(Proxy*)
~Proxy()
// это уже вызывает close()
раньше, чем ожидалосьProxy(Proxy&& other)
// движение после разрушения дает p.pResource_
значение nullptr
~Proxy()
//p
выходит за рамкиЭто не имеет смысла для меня. Я пытаюсь отследить время жизни прокси-класса, передающего задание на закрытие ресурса через конструктор перемещения от одного объекта к другому.
getProxy()
возвращает ссылку на временный объект, который выходит из области видимости в конце функции и приводит к зависанию ссылки.
Возврат по rvalue-ссылке на самом деле не приводит к перемещению чего-либо. Он просто возвращается по ссылке. Однако это отличается от возврата ссылки на lvalue, потому что выражение, вызывающее функцию, которая возвращает ссылку на rvalue, является xvalue (в отличие от lvalue). Затем xvalue (как подмножество выражений rvalue) может быть перемещен из. Если вы хотите перейти от возвращенного объекта функции, возвращающей ссылку на lvalue, вам придется использовать std::move
чтобы сделать это ценным.
Вы очень редко захотите вернуть ссылку на значение. Единственное расплывчатое использование — разрешить перемещение частного члена объекта. Если вы хотите, чтобы объект был перемещен при возврате из функции, просто верните его по значению. В вашем случае, если тип возврата getProxy
Было просто Proxy
, временный объект будет перемещен из возвращаемого объекта, а затем он будет перемещен из в p
(за исключением любого выбора).
Как у вас есть, ваш временный объект Proxy(this)
) уничтожается в конце return
Заявление — это первый вызов деструктора. Возвращенная ссылка теперь ссылается на недопустимый объект и p
построен путем перемещения из этой недействительной ссылки. Это дает вам неопределенное поведение.