在 C++ 中使用 delete 命令会导致分段错误的原因是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5394385/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What can cause a segmentation fault using delete command in C++?
提问by Zach
I've written a program that allocates a new object of the class T like this:
我写了一个程序来分配类 T 的一个新对象,如下所示:
T* obj = new T(tid);
where tid is an int
其中 tid 是一个 int
Somewhere else in my code, I'm trying to release the object I've allocated, which is inside a vector, using:
在我的代码的其他地方,我试图释放我分配的对象,它在一个向量内,使用:
delete(myVec[i]);
and then:
进而:
myVec[i] = NULL;
Sometimes it passes without any errors, and in some cases it causes a crash—a segmentation fault.
有时它通过而没有任何错误,在某些情况下它会导致崩溃 - 分段错误。
I've checked before calling delete, and that object is there—I haven't deleted it elsewhere before.
我在调用 delete 之前检查过,那个对象就在那里——我之前没有在别处删除它。
What can cause this crash?
This is my code for inserting objects of the type T to the vector:
什么会导致这次崩溃?
这是我将 T 类型的对象插入向量的代码:
_myVec is global
int add() {
int tid = _myVec.size();
T* newT = new T (tid);
if (newT == NULL){
return ERR_CODE;
}
_myVec.push_back(newT);
// _myVec.push_back(new T (tid));
return tid;
}
as it is - the program sometimes crash.
When I replace the push_back line with the commented line, and leave the rest as it is-it works.
照原样 - 程序有时会崩溃。
当我用注释行替换 push_back 行时,其余部分保持原样 - 它可以工作。
but when I replace this code with:
但是当我用以下代码替换此代码时:
int add() {
int tid = _myVec.size();
if (newT == NULL){
return ERR_CODE;
}
_myVec.push_back(new T (tid));
return tid;
}
it crashes in a different stage...
它在不同的阶段崩溃......
the newT in the second option is unused, and still - changes the whole process... what is going on here?
第二个选项中的 newT 未使用,并且仍然 - 改变了整个过程......这里发生了什么?
回答by Klaim
Segfaulting mean trying to manipulate a memory location that shouldn't be accessible to the application.
Segfaulting 意味着尝试操作应用程序不应访问的内存位置。
That means that your problem can come from three cases :
这意味着您的问题可能来自三种情况:
- Trying to do something with a pointer that points to NULL;
- Trying to do something with an uninitialized pointer;
- Trying to do something with a pointer that pointed to a now deleted object;
- 试图用指向 NULL 的指针做一些事情;
- 试图用一个未初始化的指针做一些事情;
- 尝试使用指向已删除对象的指针执行某些操作;
1) is easy to check so I assume you already do it as you nullify the pointers in the vector. If you don't do checks, then do it before the delete call. That will point the case where you are trying to delete an object twice. 3) can't happen if you set NULL to the pointer in the vector.
1) 很容易检查,所以我假设您已经在取消向量中的指针时这样做了。如果您不进行检查,请在删除调用之前进行检查。这将指出您尝试两次删除对象的情况。3) 如果将 NULL 设置为向量中的指针,则不会发生。
2) might happen too. In you case, you're using a std::vector, right? Make sure that implicit manipulations of the vector (like reallocation of the internal buffer when not big enough anymore) doesn't corrupt your list.
2)也可能发生。在您的情况下,您使用的是 std::vector ,对吗?确保对向量的隐式操作(如内部缓冲区不再足够大时的重新分配)不会破坏您的列表。
So, first check that you delete NULL pointers (note that delete(NULL) will not throw! it's the standard and valid behaviour! )- in your case you shouldn't get to the point to try to delete(NULL). Then if it never happen, check that you're not having your vector fill with pointers pointing to trash. For example, you should make sure you're familiar with the [Remove-Erase idiom][1].
因此,首先检查您是否删除了 NULL 指针(注意 delete(NULL) 不会抛出!这是标准且有效的行为!)- 在您的情况下,您不应该尝试删除(NULL)。然后,如果它永远不会发生,请检查您的向量是否填充了指向垃圾箱的指针。例如,您应该确保您熟悉 [Remove-Erase idiom][1]。
Now that you added some code I think I can see the problem :
现在您添加了一些代码,我想我可以看到问题所在:
int tid = _myVec.size();
You're using indice as ids.
您正在使用索引作为 ID。
Now, all depends on the way you delete your objects.(please show it for a more complete answer)
现在,一切都取决于您删除对象的方式。(请出示它以获得更完整的答案)
- You just set the pointer to NULL.
- You remove the pointer from the vector.
- 您只需将指针设置为 NULL。
- 您从向量中删除指针。
If you only do 1), then it should be safe (if you don't bother having a vector that grows and never get released and ids aren't re-used).
If you do 2. then this is all wrong : each time you remove an object from a vector, all the object still contains after the removed object position will be lowered by one. Making any stored id/index invalid.
如果你只做 1),那么它应该是安全的(如果你不打扰一个不断增长且永远不会被释放并且 id 不被重用的向量)。
如果您执行 2. 那么这一切都是错误的:每次从向量中删除一个对象时,在删除的对象位置将降低 1 后,所有对象仍然包含。使任何存储的 id/index 无效。
Make sure you're coherent on this point, it is certainly a source of errors.
确保你在这一点上是连贯的,这肯定是错误的来源。
回答by vlg789
that segmentation fault is most probably and memory access violation. Some reasons
该分段错误很可能是内存访问冲突。一些原因
1) object already deallocated. be sure you set that array position on NULL after delete 2) you are out of array bounds 3) if you access that array from multiple threads make sure you are synchronizing correctly
1) 对象已经释放。确保在删除后将该数组位置设置为 NULL 2) 您超出了数组边界 3) 如果您从多个线程访问该数组,请确保您正确同步
回答by Puppy
If you're completely certain that pointer points to a valid object, and that the act of deleting it causes the crash, then you have heap corruption.
如果您完全确定该指针指向一个有效对象,并且删除它的行为会导致崩溃,那么您就存在堆损坏。
回答by Matthieu M.
You should try using a ptr_vector, unlike your code, it's guaranteed to be exception-safe.
您应该尝试使用ptr_vector,与您的代码不同,它保证是异常安全的。
Hint: if you write delete
, you're doing it wrong
提示:如果你写delete
,你就做错了
回答by Baltasarq
You can't be sure that the object is still valid: the memory that was occupied by the object is not necessarily cleaned, and therefore, you can be seeing something that appears to be your object but it is not anymore.
您无法确定该对象是否仍然有效:该对象占用的内存不一定会被清除,因此,您可能会看到一些看似是您的对象但现在已经不是的东西。
You can use a mark in order to be sure that the object is still alive, and delete that mark in the destructor.
您可以使用标记以确保对象仍然存在,并在析构函数中删除该标记。
class A {
public:
static const unsigned int Inactive;
static const unsigned int Active;
A();
~A();
/* more things ...*/
private:
unsigned int mark;
};
const unsigned int A::Inactive = 0xDEADBEEF;
const unsigned int A::Active = 0x11BEBEEF;
A::A() : mark( Active )
{}
A::~A()
{
mark = Inactive;
}
This way, checking the first 4 bytes in your object you can easily verify whether your object has finished its live or not.
通过这种方式,检查对象中的前 4 个字节,您可以轻松验证您的对象是否已完成其活动。