为什么在std :: move之后将成员unique_ptr <>保留为非空值?

Ste*_*Cox 5 c++ exception unique-ptr move-semantics c++14

当我将a unique_ptr<>移入引发的函数中时,move -from指针不为空。这是正常现象吗?

这是两个显示该行为的测试程序。我可以在类的析构函数中观察到唯一的指针:

#include <memory>
#include <iostream>

void f(std::unique_ptr<int> &&) { throw "fail"; }
struct except_move_tester
{
    std::unique_ptr<int> x;
    except_move_tester()
      : x(std::make_unique<int>(0))
    {}
    ~except_move_tester() { std::cout << "x at destructor: " << x.get() << std::endl; }
    void g()
    {
        std::cout << "x at g: " << x.get() << std::endl;
        f(std::move(x));
    }
};

int main()
{
    try {
        except_move_tester t;
        t.g();
    } catch (...) {}
}
Run Code Online (Sandbox Code Playgroud)

运行时给出的输出:

x at g: 0x7f818b402ac0
x at destructor: 0x7f818b402ac0
Run Code Online (Sandbox Code Playgroud)

如果我按如下方式修改上面的清单(只是在函数调用的位置添加了一个临时名称),那么我通常会期望得到异常安全行为:

#include <memory>
#include <iostream>

void f(std::unique_ptr<int> &&) { throw "fail"; }
struct except_move_tester
{
    std::unique_ptr<int> x;
    except_move_tester()
      : x(std::make_unique<int>(0))
    {}
    ~except_move_tester() { std::cout << "x at destructor: " << x.get() << std::endl; }
    void g()
    {
        std::cout << "x at g: " << x.get() << std::endl;
        auto y = std::move(x);
        f(std::move(y));
    }
};

int main()
{
    try {
        except_move_tester t;
        t.g();
    } catch (...) {}
}
Run Code Online (Sandbox Code Playgroud)

运行时给出的输出:

x at g: 0x7f818b402ac0
x at destructor: 0x0
Run Code Online (Sandbox Code Playgroud)

我一直在假设unique_ptr是一种原子异常安全操作的情况下将其移入函数,但这似乎表明异常可能会使唯一指针处于意外状态。

son*_*yao 4

std::move只是将对象转换为右值,但不会执行移动操作。

(强调我的)

std::move用于指示一个对象t可以“从”移动,即允许将资源从 t 有效转移到另一个对象。

特别是,std::move生成一个 xvalue 表达式来标识其参数 t。它完全等同于static_cast右值引用类型的a 。

你的第二个片段有效,因为你明确地进入 xy

要修复第一个片段,您还可以显式执行移动操作,例如

void f(std::unique_ptr<int> && p) { 
    std::unique_ptr<int> t = std::move(p); // move-construct t from p
    throw "fail"; 
}
Run Code Online (Sandbox Code Playgroud)

要不就

void f(std::unique_ptr<int> p) { throw "fail"; }
Run Code Online (Sandbox Code Playgroud)

对于后者,给定f(std::move(x));,参数参数p移出。x