gpt4 book ai didi

c++ - 了解 C++ 指针生命周期/僵尸指针

转载 作者:行者123 更新时间:2023-12-01 19:50:20 25 4
gpt4 key购买 nike

观看 CppCons 后 Will Your Code Survive the Attack of the Zombie Pointers?我对指针的生命周期有点困惑,需要一些澄清。

首先一些基本的了解。评论如有错误,请指正:

int* p = new int(1);
int* q = p;
// 1) p and q are valid and one can do *p, *q
delete q;
// 2) both are invalid and cannot be dereferenced. Also the value of both is unspecified
q = new int(42); // assume it returns the same memory
// 3) Both pointers are valid again and can be dereferenced

我对 2) 感到困惑。显然它们不能被取消引用,但为什么不能使用它们的值(例如,将一个值与另一个值进行比较,甚至是不相关且有效的指针?)这在 25:38 中进行了说明。 。我在cppreference上找不到任何关于此的信息。 ,这就是我得到 3) 的地方。

注意:返回相同内存的假设不能一概而论,因为它可能会发生也可能不会发生。对于此示例,应该理所当然地认为它“随机”返回了与视频示例中的情况相同的内存,并且(也许?)下面的代码需要中断。

后进先出列表中的多线程示例代码可以在单个线程中模拟:

Node* top = ... //NodeA allocated before;
Node* newnodeC = new Node(v);
newnodeC->next = top;
delete top; top = nullptr;
// newnodeC->next is a zombie pointer
Node* newnodeD = new Node(u); // assume same memory as NodeA is returned
top = newnodeD;
if(top == newnodeC->next) // true
top = newnodeC;
// Now top->next is (still) a zombie pointer

这应该是有效的,除非 Node根据

下的规则包含非静态 const 成员或引用

If a new object is created at the address that was occupied by another object, then all pointers, references, and the name of the original object will automatically refer to the new object and, once the lifetime of the new object begins, can be used to manipulate the new object, but only if the following conditions are satisfied [which they are]

那么为什么这是一个僵尸指针并且被认为是 UB?

上面的(单线程)压缩代码是否可以通过 newnodeC->next = std::launder(newnodeC->next) 来修复(如果有 const 成员)截至

If the conditions listed above are not met, a valid pointer to the new object may still be obtained by applying the pointer optimization barrier std::launder

我希望这能够修复“僵尸指针”,并且编译器不会发出赋值指令,而只是将其视为优化障碍(例如,当函数内联并且再次访问 const 成员时)

总而言之:我以前没有听说过“僵尸指针”。我是否正确,不能使用任何指向已销毁/已删除对象的指针(用于读取[指针值]和取消引用[读取受指点]),除非重新分配指针或使用在那里重新创建的相同对象类型重新分配内存(并且没有 const/reference 成员)?这不能通过 C++17 修复吗 std::launder已经? (裸露多线程问题)

另外:在3)在第一个代码中将 if(p==q)甚至普遍有效?因为根据我对视频(第二部分)的理解,阅读 p 是无效的。 .

编辑:作为我很确定 UB 发生的解释:再次假设纯粹偶然,相同的内存随 new 返回。 :

// Global
struct Node{
const int value;
};
Node* globalPtr = nullptr;
// In some func
Node* ptr = new Node{42};
globalPtr = ptr;
const int value = ptr->value;
foo(value);
// Possibly on another thread (if multi-threaded assume proper synchronisation so that this scenario happens)
delete globalPtr;
globalPtr = new Node{1337}; // Assume same memory returned
// First thread again (and maybe on serial code too)
if(ptr == globalPtr)
foo(ptr->value);
else
foo(globalPtr->value);

根据视频,delete globalPtr之后还有ptr是一个“僵尸指针”并且不能被使用(又名“将是UB”)。充分优化的编译器可以利用这一点并假设指针对象从未​​被释放(特别是当删除/新建发生在另一个函数/线程/...上时)并优化 foo(ptr->value)foo(42)

另请注意提到的 Defect Report 260 :

Where a pointer value becomes indeterminate because the object pointed to has reached the end of its lifetime, all objects whose effective type is a pointer and that point to the same object acquire an indeterminate value. Thus p at point X, and p, q, and r at point Z, can all change their value.

我认为这是明确的解释:delete globalPtr之后ptr 的值也是不确定的。但这如何与

If a new object is created at the address that was occupied by another object, then all pointers [...] of the original object will automatically refer to the new object and[...] can be used to manipulate the new object

最佳答案

已删除的指针值具有无效的指针值,而不是未指定的值。

从 C++17 开始,无效指针值的行为在 [basic.stc]/4 中定义:

Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior.

因此,尝试比较两个无效指针具有实现定义的行为。有一个脚注澄清此行为可能包括运行时错误。

在您的第一个代码段中,p 在删除后有一个无效的指针值;您对 q 所做的任何操作都与此无关。无效的指针值无法神奇地再次变得有效。无法(在标准 C++ 的范围内)确定新的分配是否与先前的分配位于“同一位置”。

std::launder 没有帮助;您再次使用了无效的指针值,因此触发了实现定义的行为。

也许您可以查阅您的实现文档,看看它如何定义此行为。

在您的问题中,您提到了 C DR 260,但这无关紧要。 C 是一种与 C++ 不同的语言。在 C++ 中,已删除的指针具有无效的指针值,而不是不确定的值

关于c++ - 了解 C++ 指针生命周期/僵尸指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58414316/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com