std::unique_ptr 是否在其析构函数中将其基础指针设置为 nullptr?
Does std::unique_ptr set its underlying pointer to nullptr inside its destructor?
在实现我自己的unique_ptr
时(只是为了好玩),我发现它无法通过libstdcxx
的这个测试文件:
struct A;
struct B
{
std::unique_ptr<A> a;
};
struct A
{
B* b;
~A() { VERIFY(b->a != nullptr); }
};
void test01()
{
B b;
b.a.reset(new A);
b.a->b = &b;
}
GCC 愉快地通过了这个测试文件(当然,这个文件来自 libstdcxx),而 clang 在VERIFY
部分失败了。
问题:
- 是依赖于实现还是未定义的行为?
- 我想这个后置条件(
b->a != nullptr
)对gcc很重要,否则它不会有它的测试文件,但我不知道它背后是什么。它与优化有关吗?我知道许多UB都是为了更好的优化。
clang
(libc ++)在这一点上似乎不合规,因为标准说:
[unique.ptr.single.dtor]
~unique_ptr();
要求:表达式
get_deleter()(get())
应格式正确,应具有明确定义的行为,并且不得引发异常。 [注意:使用default_delete
要求T
是完整的类型。 —尾注]效果:如果
get() == nullptr
则没有效果。 否则get_deleter()(get())
.
所以析构函数应该等价于get_deleter()(get())
,这意味着b->a
不能在A
的析构函数中nullptr
(delete
指令称为内部get_deleter()
)。
附带说明一下,clang
(libc++)和gcc
(libstdc++)在销毁std::unique_ptr
时都设置了指向nullptr
的指针,但这里有gcc
析构函数:
auto& __ptr = _M_t._M_ptr();
if (__ptr != nullptr)
get_deleter()(__ptr);
__ptr = pointer();
。这是clang
(致电reset()
):
pointer __tmp = __ptr_.first();
__ptr_.first() = pointer();
if (__tmp)
__ptr_.second()(__tmp);
如您所见,gcc
首先删除然后分配给nullptr
(pointer()
),而clang
首先分配给nullptr
(pointer()
),然后删除1。
1pointer
是对应于Deleter::pointer
的别名,如果存在,或者只是T*
。
libstdc++ 和 libc++ 都是一致的,因为这是定义良好的程序无法观察到的。在析构函数的执行过程中,[res.on.objects]/2 禁止任何尝试观察(或修改,就此而言)unique_ptr
对未定义行为的痛苦的状态:
如果访问了标准库类型的对象,并且对象生存期的开始未在访问之前发生,或者访问未在对象的生存期结束之前发生,则除非另有指定,否则未定义行为。
事实上,unique_ptr
的析构函数是最初(由 LWG2224)添加这一段的原因。
此外,销毁完成后,它所占用的存储内容在 [basic.life]/4 中不确定:
本文档中归属于对象和引用的属性仅适用于给定对象或引用在其生存期内。
对销毁后std::unique_ptr<>
占用的内存的最终状态没有要求。将其设置为 null 是没有意义的,因为内存正在返回到分配它的位置。GCC 可能会检查它是否不为空,以确保没有人添加不必要的代码来清除它。在适当的情况下,在不需要时强制清除值可能会导致性能下降。
- 将指针设置为"nullptr"并不能防止双重删除?
- C++默认情况下,指针类型数组的元素是否保证初始化为 nullptr?
- 空指针常量 (nullptr)、空指针值和空成员指针值之间有什么区别?
- 检查模板中 nullptr 的函数指针,了解任何类型的可调用对象
- CURLOPT_INTERLEAVEFUNCTION回调函数始终接收 nullptr 作为用户数据指针
- boost::spirit指针属性是用nullptr初始化的吗?
- unique_ptr<T>::get() 返回的指针在原始unique_ptr被销毁后不是 nullptr
- 在C++中将指针数组的所有元素设置为 nullptr
- 以原子方式交换指针与 nullptr
- 指向抽象类的指针数组:指向 nullptr 或不指向 nullptr (C++)
- 仅当指针不是 nullptr 时才调用方法
- C++链表指针始终为 nullptr
- 为什么分配了 nullptr 的指针可以调用成员函数?
- 空向量占用的空间是否与指向当前设置为 nullptr 的类型的指针一样多
- 如何使用nullptr初始化同一类对象的静态指针数组?
- 为什么我不能使用 nullptr 初始化自动推导的指针?
- std::unique_ptr 是否在其析构函数中将其基础指针设置为 nullptr?
- 我可以得到指向 nullptr 的指针的指针吗,它是否有效
- C++ 仅设置对象指向 nullptr 的指针
- 指向自定义类型的静态指针在初始化后使用相同类型的静态非空指针保持 nullptr