- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
观看 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
根据
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/
我刚接触 C 语言几周,所以对它还很陌生。 我见过这样的事情 * (variable-name) = -* (variable-name) 在讲义中,但它到底会做什么?它会否定所指向的值吗? 最佳答案
我有一个指向内存地址的void 指针。然后,我做 int 指针 = void 指针 float 指针 = void 指针 然后,取消引用它们以获取值。 { int x = 25; vo
我正在与计算机控制的泵进行一些串行端口通信,我用来通信的 createfile 函数需要将 com 端口名称解析为 wchar_t 指针。 我也在使用 QT 创建一个表单并获取 com 端口名称作为
#include "stdio.h" #include "malloc.h" int main() { char*x=(char*)malloc(1024); *(x+2)=3; --
#include #include main() { int an_int; void *void_pointer = &an_int; double *double_ptr = void
对于每个时间步长,我都有一个二维矩阵 a[ix][iz],ix 从 0 到 nx-1 和 iz 从 0 到 nz-1。 为了组装所有时间步长的矩阵,我定义了一个长度为 nx*nz*nt 的 3D 指针
我有一个函数,它接受一个指向 char ** 的指针并用字符串填充它(我猜是一个字符串数组)。 *list_of_strings* 在函数内部分配内存。 char * *list_of_strings
我试图了解当涉及到字符和字符串时,内存分配是如何工作的。 我知道声明的数组的名称就像指向数组第一个元素的指针,但该数组将驻留在内存的堆栈中。 另一方面,当我们想要使用内存堆时,我们使用 malloc,
我有一个 C 语言的 .DLL 文件。该 DLL 中所有函数所需的主要结构具有以下形式。 typedef struct { char *snsAccessID; char *
指针, C语言的精髓 莫队先咕几天, 容我先讲完树剖 (因为后面树上的东西好多都要用树剖求 LCA). 什么是指针 保存变量地址的变量叫做指针. 这是大概的定义, 但是Defad认为
我得到了以下数组: let arr = [ { children: [ { children: [], current: tru
#include int main(void) { int i; int *ptr = (int *) malloc(5 * sizeof(int)); for (i=0;
我正在编写一个程序,它接受一个三位数整数并将其分成两个整数。 224 将变为 220 和 4。 114 将变为 110 和 4。 基本上,您可以使用模数来完成。我写了我认为应该工作的东西,编译器一直说
好吧,我对 C++ 很陌生,我确定这个问题已经在某个地方得到了回答,而且也很简单,但我似乎找不到答案.... 我有一个自定义数组类,我将其用作练习来尝试了解其工作原理,其定义如下: 标题: class
1) this 指针与其他指针有何不同?据我了解,指针指向堆中的内存。如果有指向它们的指针,这是否意味着对象总是在堆中构造? 2)我们可以在 move 构造函数或 move 赋值中窃取this指针吗?
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: C : pointer to struct in the struct definition 在我的初学者类
我有两个指向指针的结构指针 typedef struct Square { ... ... }Square; Square **s1; //Representing 2D array of say,
变量在内存中是如何定位的?我有这个代码 int w=1; int x=1; int y=1; int z=1; int main(int argc, char** argv) { printf
#include #include main() { char *q[]={"black","white","red"}; printf("%s",*q+3); getch()
我在“C”类中有以下函数 class C { template void Func1(int x); template void Func2(int x); }; template void
我是一名优秀的程序员,十分优秀!