为什么unique_ptr和shared_ptr不会使它们的构造指针无效? [英] Why unique_ptr and shared_ptr do not invalidate the pointer they are constructed from?
问题描述
注意:这是一个 API设计问题 ,出于问题的考虑,该设计基于unique_ptr
和share_ptr
的构造函数的设计,但是并不打算提出对当前规范的任何更改.
A note: this is an API design question, riding on the design of the constructors of unique_ptr
and share_ptr
for the sake of the question, but not aiming to propose any change to their current specifications.
尽管通常建议使用make_unique
和make_shared
,但unique_ptr
和shared_ptr
都可以由原始指针构造.
Though it would usually be advisable to use make_unique
and make_shared
, both unique_ptr
and shared_ptr
can be constructed from a raw pointer.
两者都按值获取指针并进行复制.两者都允许(即:不阻止)继续使用构造函数中传递给它们的原始指针.
Both get the pointer by value and copy it. Both allow (i.e. in the sense of: do not prevent) a continuance usage of the original pointer passed to them in the constructor.
以下代码使用double free进行编译和结果:
The following code compiles and results with double free:
int* ptr = new int(9);
std::unique_ptr<int> p { ptr };
// we forgot that ptr is already being managed
delete ptr;
如果
和shared_ptr
的相关构造函数希望将原始指针作为 rvalue 来获取,例如shared_ptr
都可以防止上述情况.对于unique_ptr:
Both unique_ptr
and shared_ptr
could prevent the above if their relevant constructors would expect to get the raw pointer as an rvalue, e.g. for unique_ptr:
template<typename T>
class unique_ptr {
T* ptr;
public:
unique_ptr(T*&& p) : ptr{p} {
p = nullptr; // invalidate the original pointer passed
}
// ...
因此,原始代码无法编译为 lvalue 无法绑定到 rvalue ,但是使用std::move
可以编译代码,同时更加冗长和安全:
Thus, the original code would not compile as an lvalue cannot bind to an rvalue, but using std::move
the code compiles, while being more verbose and more secured:
int* ptr = new int(9);
std::unique_ptr<int> p { std::move(ptr) };
if (!ptr) {
// we are here, since ptr was invalidated
}
很明显,用户可以使用智能指针来处理许多其他错误. 您通常应该知道如何正确使用语言提供的工具,而 C ++并不是为了监视您等而设计的.
It is clear that there can be dozens of other bugs a user can do with smart pointers. The commonly used argument of you should know how to properly use the tools provided by the language, and C++ is not designed to watch over you etc.
但是,似乎仍然可以选择防止该简单错误并鼓励使用make_shared
和make_unique
的方法.甚至在C ++ 14中添加make_unique
之前,仍然总是可以选择不使用指针变量的直接分配,例如:
But still, it seems that there could have been an option for preventing this simple bug and to encourage usage of make_shared
and make_unique
. And even before make_unique
was added in C++14, there is still always the option of direct allocation without a pointer variable, as:
auto ptr = std::unique_ptr<int>(new int(7));
似乎向指针请求右值引用作为构造函数参数可能会增加一些额外的安全性.此外,随着我们获得传递的指针的所有权,获取 rvalue 的语义似乎更加准确.
It seems that requesting rvalue reference to a pointer as the constructor parameter could add a bit of an extra safety. Moreover, the semantics of getting rvalue seems to be more accurate as we take ownership of the pointer that is passed.
提到标准为什么不采用这种更安全的方法?
一个可能的原因可能是上面建议的方法将阻止从 const指针 创建unique_ptr
,即以下代码将无法使用建议的方法进行编译:
A possible reason might be that the approach suggested above would prevent creating a unique_ptr
from const pointers, i.e. the following code would fail to compile with the proposed approach:
int* const ptr = new int(9);
auto p = std::unique_ptr { std::move(ptr) }; // cannot bind `const rvalue` to `rvalue`
但是,我认为这似乎是一个值得忽略的罕见情况.
But this seems to be a rare scenario worth neglecting, I believe.
或者,如果需要从const指针支持初始化是强烈反对所建议方法的论点,那么使用以下方法仍可以实现较小的步骤:
Alternatively, in case the need to support initialization from a const pointer is a strong argument against the proposed approach, then a smaller step could still be achieved with:
unique_ptr(T* const&& p) : ptr{p} {
// ...without invalidating p, but still better semantics?
}
推荐答案
我认为答案很简单:零开销.不需要此更改即可使unique_ptr起作用,因此标准不需要此更改.如果您认为这样做可以提高安全性使其值得,那么可以要求您的实现添加它(也许在特殊的编译标志下).
I think the answer is simple: zero overhead. This change isn't needed for unique_ptr to be functional, so the standard doesn't require it. If you think this improves safety enough to worth it, you can ask your implementation to add it (maybe under a special compilation flag).
顺便说一句,我希望静态分析器了解的足够多,可以针对这种代码模式发出警告.
BTW, I'd expect static analyzers to know enough to warn against this code pattern.
这篇关于为什么unique_ptr和shared_ptr不会使它们的构造指针无效?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!