为什么成员 unique_ptr<> 在 std::move 之后被保留为非 null 到抛出函数?
Why is a member unique_ptr<> left non-null after std::move to a throwing function?
当我将 unique_ptr<>
移动到抛出的函数中时,移出指针保留为非空。这是正常行为吗?
这里有两个显示该行为的测试程序。我可以在 class:
的析构函数中观察到唯一指针
#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 (...) {}
}
当 运行 给出输出时:
x at g: 0x7f818b402ac0
x at destructor: 0x7f818b402ac0
如果我按如下方式修改上面的列表(只是在函数调用的位置添加了一个临时的),我会得到我通常期望的异常安全行为:
#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 (...) {}
}
当 运行 给出输出时:
x at g: 0x7f818b402ac0
x at destructor: 0x0
我一直在将 unique_ptr 移动到函数中,假设它是一种原子异常安全操作,但这似乎表明异常可能会使唯一指针处于意外状态。
std::move
只是将对象转换为右值,不会执行移动操作。
(强调我的)
std::move
is used to indicate that an object t
may be "moved from", i.e. allowing the efficient transfer of resources from t to another object.
In particular, std::move
produces an xvalue expression that identifies its argument t. It is exactly equivalent to a static_cast
to an rvalue reference type.
您的第二个代码段有效,因为您 明确地将 x
移动到 y
中。
要修复第一个片段,您还可以明确执行移动操作,例如
void f(std::unique_ptr<int> && p) {
std::unique_ptr<int> t = std::move(p); // move-construct t from p
throw "fail";
}
或者只是
void f(std::unique_ptr<int> p) { throw "fail"; }
对于后者,给定 f(std::move(x));
,参数 p
从 参数 x
.
移动
当我将 unique_ptr<>
移动到抛出的函数中时,移出指针保留为非空。这是正常行为吗?
这里有两个显示该行为的测试程序。我可以在 class:
的析构函数中观察到唯一指针#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 (...) {}
}
当 运行 给出输出时:
x at g: 0x7f818b402ac0
x at destructor: 0x7f818b402ac0
如果我按如下方式修改上面的列表(只是在函数调用的位置添加了一个临时的),我会得到我通常期望的异常安全行为:
#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 (...) {}
}
当 运行 给出输出时:
x at g: 0x7f818b402ac0
x at destructor: 0x0
我一直在将 unique_ptr 移动到函数中,假设它是一种原子异常安全操作,但这似乎表明异常可能会使唯一指针处于意外状态。
std::move
只是将对象转换为右值,不会执行移动操作。
(强调我的)
std::move
is used to indicate that an objectt
may be "moved from", i.e. allowing the efficient transfer of resources from t to another object.In particular,
std::move
produces an xvalue expression that identifies its argument t. It is exactly equivalent to astatic_cast
to an rvalue reference type.
您的第二个代码段有效,因为您 明确地将 x
移动到 y
中。
要修复第一个片段,您还可以明确执行移动操作,例如
void f(std::unique_ptr<int> && p) {
std::unique_ptr<int> t = std::move(p); // move-construct t from p
throw "fail";
}
或者只是
void f(std::unique_ptr<int> p) { throw "fail"; }
对于后者,给定 f(std::move(x));
,参数 p
从 参数 x
.