Basic Question: when does a program call a class' destructor method in C++? I have been told that it is called whenever an object goes out of scope or is subjected to a delete
基本问题:在c++中程序何时调用类的析构函数?我被告知,每当一个对象超出范围或被删除时,就调用它
More specific questions:
更具体的问题:
1) If the object is created via a pointer and that pointer is later deleted or given a new address to point to, does the object that it was pointing to call its destructor (assuming nothing else is pointing to it)?
1)如果对象是通过一个指针创建的,而该指针随后被删除或被赋予一个新的地址来指向它,那么它所指向的对象是否会调用它的析构函数(假设没有其他东西指向它)?
2) Following up on question 1, what defines when an object goes out of scope (not regarding to when an object leaves a given {block}). So, in other words, when is a destructor called on an object in a linked list?
2)根据问题1,什么定义了对象何时超出范围(而不是对象何时离开给定的{block})。那么,换句话说,一个析构函数何时会调用链表中的一个对象呢?
3) Would you ever want to call a destructor manually?
你想要手动调用析构函数吗?
9 个解决方案
#1
51
1) If the object is created via a pointer and that pointer is later deleted or given a new address to point to, does the object that it was pointing to call its destructor (assuming nothing else is pointing to it)?
1)如果对象是通过一个指针创建的,而该指针随后被删除或被赋予一个新的地址来指向它,那么它所指向的对象是否会调用它的析构函数(假设没有其他东西指向它)?
It depends on the type of pointers. For example, smart pointers often delete their objects when they are deleted. Ordinary pointers do not. The same is true when a pointer is made to point to a different object. Some smart pointers will destroy the old object, or will destroy it if it has no more references. Ordinary pointers have no such smarts. They just hold an address and allow you to perform operations on the objects they point to by specifically doing so.
这取决于指针的类型。例如,当对象被删除时,智能指针通常会删除它们的对象。普通的指针不。当一个指针指向一个不同的对象时也是如此。一些智能指针将会破坏旧的对象,或者如果它没有更多的引用将会破坏它。普通的指针没有这样的聪明。它们只保留一个地址,允许您对它们所指向的对象执行操作。
2) Following up on question 1, what defines when an object goes out of scope (not regarding to when an object leaves a given {block}). So, in other words, when is a destructor called on an object in a linked list?
2)根据问题1,什么定义了对象何时超出范围(而不是对象何时离开给定的{block})。那么,换句话说,一个析构函数何时会调用链表中的一个对象呢?
That's up to the implementation of the linked list. Typical collections destroy all their contained objects when they are destroyed.
这取决于链表的实现。典型的集合在它们被销毁时销毁它们所包含的所有对象。
So, a linked list of pointers would typically destroy the pointers but not the objects they point to. (Which may be correct. They may be references by other pointers.) A linked list specifically designed to contain pointers, however, might delete the objects on its own destruction.
所以,一个指针链表通常会破坏指针,而不是它们指向的对象。(可能是正确的。它们可能是其他指针的引用)但是,一个专门设计用来包含指针的链表可能会删除它自身销毁的对象。
A linked list of smart pointers could automatically delete the objects when the pointers are deleted, or do so if they had no more references. It's all up to you to pick the pieces that do what you want.
当指针被删除时,一个链接的智能指针列表可以自动删除对象,或者如果指针没有更多的引用就可以删除对象。你可以选择做你想做的事情。
3) Would you ever want to call a destructor manually?
你想要手动调用析构函数吗?
Sure. One example would be if you want to replace an object with another object of the same type but don't want to free memory just to allocate it again. You can destroy the old object in place and construct a new one in place. (However, generally this is a bad idea.)
确定。一个例子是,如果你想用相同类型的另一个对象替换一个对象,但又不想释放内存来重新分配它。您可以在适当的地方破坏旧的对象并在适当的地方构造一个新的对象。(不过,总的来说,这是个坏主意。)
// pointer is destroyed because it goes out of scope,
// but not the object it pointed to. memory leak
if (1) {
Foo *myfoo = new Foo("foo");
}
// pointer is destroyed because it goes out of scope,
// object it points to is deleted. no memory leak
if(1) {
Foo *myfoo = new Foo("foo");
delete myfoo;
}
// no memory leak, object goes out of scope
if(1) {
Foo myfoo("foo");
}
#2
11
Others have already addressed the other issues, so I'll just look at one point: do you ever want to manually delete an object.
其他人已经解决了其他问题,所以我只关注一点:您是否想要手动删除一个对象。
The answer is yes. @DavidSchwartz gave one example, but it's a fairly unusual one. I'll give an example that's under the hood of what a lot of C++ programmers use all the time: std::vector
(and std::deque
, though it's not used quite as much).
答案是肯定的。@DavidSchwartz给出了一个例子,但这是一个很不寻常的例子。我将给出一个例子,这是很多c++程序员一直使用的一个例子:std::vector(和std: deque,虽然没有那么多使用)。
As most people know, std::vector
will allocate a larger block of memory when/if you add more items than its current allocation can hold. When it does this, however, it has a block of memory that's capable of holding more objects than are currently in the vector.
正如大多数人所知道的,当/如果您添加的项超过其当前分配的容量时,std:::vector将分配更大的内存块。然而,当它这样做时,它有一个内存块,它可以容纳比当前向量中更多的对象。
To manage that, what vector
does under the covers is allocate raw memory via the Allocator
object (which, unless you specify otherwise, means it uses ::operator new
). Then, when you use (for example) push_back
to add an item to the vector
, internally the vector uses a placement new
to create an item in the (previously) unused part of its memory space.
为了管理这一点,在覆盖层下的向量是通过分配器对象来分配原始内存(除非你指定否则,这意味着它使用::new)。然后,当您使用(例如)push_back向向量添加一个项时,在内部,向量使用一个新的位置在(先前)未使用的内存空间中创建一个项。
Now, what happens when/if you erase
an item from the vector? It can't just use delete
-- that would release its entire block of memory; it needs to destroy one object in that memory without destroying any others, or releasing any of the block of memory it controls (for example, if you erase
5 items from a vector, then immediately push_back
5 more items, it's guaranteed that the vector will not reallocate memory when you do so.
现在,如果你从向量中擦掉一个项会发生什么?它不能只使用delete——这会释放整个内存块;它需要毁灭一个对象在内存不破坏任何其他人,或释放任何的内存块,它控制(例如,如果您删除5项从一个矢量,然后立刻push_back 5项,它是保证矢量不会重新分配内存,当你这样做。
To do that, the vector directly destroys the objects in the memory by explicitly calling the destructor, not by using delete
.
为此,向量直接通过显式地调用析构函数(而不是使用delete)来破坏内存中的对象。
If, perchance, somebody else were to write a container using contiguous storage roughly like a vector
does (or some variant of that, like std::deque
really does), you'd almost certainly want to use the same technique.
如果有人像向量那样使用连续存储来编写容器(或者类似于std::deque),那么您几乎肯定希望使用相同的技术。
Just for example, let's consider how you might write code for a circular ring-buffer.
例如,让我们考虑如何为循环环缓冲区编写代码。
#ifndef CBUFFER_H_INC
#define CBUFFER_H_INC
template <class T>
class circular_buffer {
T *data;
unsigned read_pos;
unsigned write_pos;
unsigned in_use;
const unsigned capacity;
public:
circular_buffer(unsigned size) :
data((T *)operator new(size * sizeof(T))),
read_pos(0),
write_pos(0),
in_use(0),
capacity(size)
{}
void push(T const &t) {
// ensure there's room in buffer:
if (in_use == capacity)
pop();
// construct copy of object in-place into buffer
new(&data[write_pos++]) T(t);
// keep pointer in bounds.
write_pos %= capacity;
++in_use;
}
// return oldest object in queue:
T front() {
return data[read_pos];
}
// remove oldest object from queue:
void pop() {
// destroy the object:
data[read_pos++].~T();
// keep pointer in bounds.
read_pos %= capacity;
--in_use;
}
// release the buffer:
~circular_buffer() { operator delete(data); }
};
#endif
Unlike the standard containers, this uses operator new
and operator delete
directly. For real use, you probably do want to use an allocator class, but for the moment it would do more to distract than contribute (IMO, anyway).
与标准容器不同,它直接使用操作符new和操作符delete。对于真正的用途,您可能确实希望使用分配器类,但是就目前而言,它所做的更多的是分散注意力而不是贡献(无论如何,在IMO上)。
#3
5
- When you create an object with
new
, you are responsible for callingdelete
. When you create an object withmake_shared
, the resultingshared_ptr
is responsible for keeping count and callingdelete
when the use count goes to zero. - 当您用new创建一个对象时,您负责调用delete。当您使用make_shared创建一个对象时,产生的shared_ptr负责在使用计数为0时保持计数并调用delete。
- Going out of scope does mean leaving a block. This is when the destructor is called, assuming that the object was not allocated with
new
(i.e. it is a stack object). - 超出范围意味着离开一个块。这就是调用析构函数时的情况,假设对象没有被分配给new(例如,它是一个堆栈对象)。
- About the only time when you need to call a destructor explicitly is when you allocate the object with a placement
new
. - 在您需要显式地调用析构函数时,只有当您将对象分配到新位置时。
#4
3
1) Objects are not created 'via pointers'. There is a pointer that is assigned to any object you 'new'. Assuming this is what you mean, if you call 'delete' on the pointer, it will actually delete (and call the destructor on) the object the pointer dereferences. If you assign the pointer to another object there will be a memory leak; nothing in C++ will collect your garbage for you.
1)对象不是通过指针创建的。有一个指针被分配给任何你“新”的对象。假设这是您的意思,如果您在指针上调用“delete”,它实际上会删除(并调用析构函数)对象的指针去引用。如果将指针分配给另一个对象,则会出现内存泄漏;c++里没有东西会帮你收集垃圾。
2) These are two separate questions. A variable goes out of scope when the stack frame it's declared in is popped off the stack. Usually this is when you leave a block. Objects in a heap never go out of scope, though their pointers on the stack may. Nothing in particular guarantees that a destructor of an object in a linked list will be called.
这是两个独立的问题。当在堆栈中声明的堆栈帧从堆栈中弹出时,变量就会超出作用域。通常这是你离开一个街区的时候。堆中的对象永远不会超出范围,尽管堆栈上的指针可能会超出范围。没有什么特别保证会调用链表中对象的析构函数。
3) Not really. There may be Deep Magic that would suggest otherwise, but typically you want to match up your 'new' keywords with your 'delete' keywords, and put everything in your destructor necessary to make sure it properly cleans itself up. If you don't do this, be sure to comment the destructor with specific instructions to anyone using the class on how they should clean up that object's resources manually.
3)没有。可能会有一些深层次的魔力,但通常情况下,你想要把“新的”关键字和“删除”关键字匹配起来,并把所有必要的东西都放到析构函数中,以确保它能正确地清理自己。如果您不这样做,请确保对使用该类的任何使用该类的人员使用特定的指令对其进行注释,以手动清理该对象的资源。
#5
3
To give a detailed answer to question 3: yes, there are (rare) occasions when you might call the destructor explicitly, in particular as the counterpart to a placement new, as dasblinkenlight observes.
对于问题3给出一个详细的答案:是的,有(很少的)情况,你可以明确地调用析构函数,特别是作为一个新的位置,正如dasblinkenlight所观察到的。
To give a concrete example of this:
举一个具体的例子:
#include <iostream>
#include <new>
struct Foo
{
Foo(int i_) : i(i_) {}
int i;
};
int main()
{
// Allocate a chunk of memory large enough to hold 5 Foo objects.
int n = 5;
char *chunk = static_cast<char*>(::operator new(sizeof(Foo) * n));
// Use placement new to construct Foo instances at the right places in the chunk.
for(int i=0; i<n; ++i)
{
new (chunk + i*sizeof(Foo)) Foo(i);
}
// Output the contents of each Foo instance and use an explicit destructor call to destroy it.
for(int i=0; i<n; ++i)
{
Foo *foo = reinterpret_cast<Foo*>(chunk + i*sizeof(Foo));
std::cout << foo->i << '\n';
foo->~Foo();
}
// Deallocate the original chunk of memory.
::operator delete(chunk);
return 0;
}
The purpose of this kind of thing is to decouple memory allocation from object construction.
这种方法的目的是将内存分配与对象结构分离开来。
#6
2
-
Pointers -- Regular pointers don't support RAII. Without an explicit
delete
, there will be garbage. Fortunately C++ has auto pointers that handle this for you!指针——常规指针不支持RAII。没有显式删除,就会有垃圾。幸运的是,c++有自动指针为您处理这个!
-
Scope -- Think of when a variable becomes invisible to your program. Usually this is at the end of
{block}
, as you point out.范围——考虑当一个变量对程序不可见时。通常这是在{block}的末尾,正如您所指出的。
-
Manual destruction -- Never attempt this. Just let scope and RAII do the magic for you.
手动销毁——千万不要这样做。让scope和RAII为你施展魔法。
#7
1
Whenever you use "new", that is, attach an address to a pointer, or to say, you claim space on the heap, you need to "delete" it.
1.yes, when you delete something, the destructor is called.
2.When the destructor of the linked list is called, it's objects' destructor is called. But if they are pointers, you need to delete them manually. 3.when the space is claimed by "new".
无论何时使用“new”,也就是说,将一个地址附加到一个指针上,或者说,您在堆上声明了空间,您需要“删除”它。1。是的,当你删除一些东西时,会调用析构函数。2。当链表的析构函数被调用时,它的对象的析构函数被调用。但如果它们是指针,则需要手动删除它们。3所示。当空间被“new”占据时。
#8
0
Yes, a destructor (a.k.a. dtor) is called when an object goes out of scope if it is on the stack or when you call delete
on a pointer to an object.
是的,当一个对象超出范围(如果它在堆栈上)或当你调用指向一个对象的指针delete时,会调用析构函数(又名dtor)。
-
If the pointer is deleted via
delete
then the dtor will be called. If you reassign the pointer without callingdelete
first, you will get a memory leak because the object still exists in memory somewhere. In the latter instance, the dtor is not called.如果通过delete删除指针,则将调用dtor。如果您重新分配指针而不首先调用delete,您将会得到内存泄漏,因为对象仍然存在于内存中的某个地方。在后一个实例中,不调用dtor。
-
A good linked list implementation will call the dtor of all objects in the list when the list is being destroyed (because you either called some method to destory it or it went out of scope itself). This is implementation dependent.
一个好的链表实现会在链表被销毁时调用链表中所有对象的dtor(因为您或者调用了一些方法来销毁它,或者它本身超出了范围)。这是由实现决定的。
-
I doubt it, but I wouldn't be surprised if there is some odd circumstance out there.
我对此表示怀疑,但如果有什么奇怪的情况发生,我也不会感到惊讶。
#9
0
If the object is created not via a pointer(for example,A a1 = A();),the destructor is called when the object is destructed, always when the function where the object lies is finished.for example:
如果对象不是通过指针创建的(例如,a1 = a();),则在对象被析构时调用析构函数,通常是在对象所在的函数完成时。例如:
void func()
{
...
A a1 = A();
...
}//finish
the destructor is called when code is execused to line "finish".
If the object is created via a pointer(for example,A * a2 = new A();),the destructor is called when the pointer is deleted(delete a2;).If the point is not deleted by user explictly or given a new address before deleting it, the memory leak is occured. That is a bug.
In a linked list, if we use std::list<>, we needn't care about the desctructor or memory leak because std::list<> has finished all of these for us. In a linked list written by ourselves, we should write the desctructor and delete the pointer explictly.Otherwise, it will cause memory leak.
We rarely call a destructor manually. It is a function providing for the system.
Sorry for my poor English!
当代码执行为行“finish”时,将调用析构函数。如果通过指针创建对象(例如,* a2 = new a();),则在删除指针时调用析构函数(删除a2;)。如果用户在删除该点之前没有明确地删除它或给它一个新地址,则会发生内存泄漏。这是一个错误。在链表中,如果我们使用std::list<>,我们不需要关心desctructor或内存泄漏,因为std::list<>已经为我们完成了所有这些。在我们自己编写的链表中,我们应该编写desctructor并明确地删除指针。否则,它将导致内存泄漏。我们很少手动调用析构函数。它是一个为系统提供的函数。对不起,我的英语很差!
#1
51
1) If the object is created via a pointer and that pointer is later deleted or given a new address to point to, does the object that it was pointing to call its destructor (assuming nothing else is pointing to it)?
1)如果对象是通过一个指针创建的,而该指针随后被删除或被赋予一个新的地址来指向它,那么它所指向的对象是否会调用它的析构函数(假设没有其他东西指向它)?
It depends on the type of pointers. For example, smart pointers often delete their objects when they are deleted. Ordinary pointers do not. The same is true when a pointer is made to point to a different object. Some smart pointers will destroy the old object, or will destroy it if it has no more references. Ordinary pointers have no such smarts. They just hold an address and allow you to perform operations on the objects they point to by specifically doing so.
这取决于指针的类型。例如,当对象被删除时,智能指针通常会删除它们的对象。普通的指针不。当一个指针指向一个不同的对象时也是如此。一些智能指针将会破坏旧的对象,或者如果它没有更多的引用将会破坏它。普通的指针没有这样的聪明。它们只保留一个地址,允许您对它们所指向的对象执行操作。
2) Following up on question 1, what defines when an object goes out of scope (not regarding to when an object leaves a given {block}). So, in other words, when is a destructor called on an object in a linked list?
2)根据问题1,什么定义了对象何时超出范围(而不是对象何时离开给定的{block})。那么,换句话说,一个析构函数何时会调用链表中的一个对象呢?
That's up to the implementation of the linked list. Typical collections destroy all their contained objects when they are destroyed.
这取决于链表的实现。典型的集合在它们被销毁时销毁它们所包含的所有对象。
So, a linked list of pointers would typically destroy the pointers but not the objects they point to. (Which may be correct. They may be references by other pointers.) A linked list specifically designed to contain pointers, however, might delete the objects on its own destruction.
所以,一个指针链表通常会破坏指针,而不是它们指向的对象。(可能是正确的。它们可能是其他指针的引用)但是,一个专门设计用来包含指针的链表可能会删除它自身销毁的对象。
A linked list of smart pointers could automatically delete the objects when the pointers are deleted, or do so if they had no more references. It's all up to you to pick the pieces that do what you want.
当指针被删除时,一个链接的智能指针列表可以自动删除对象,或者如果指针没有更多的引用就可以删除对象。你可以选择做你想做的事情。
3) Would you ever want to call a destructor manually?
你想要手动调用析构函数吗?
Sure. One example would be if you want to replace an object with another object of the same type but don't want to free memory just to allocate it again. You can destroy the old object in place and construct a new one in place. (However, generally this is a bad idea.)
确定。一个例子是,如果你想用相同类型的另一个对象替换一个对象,但又不想释放内存来重新分配它。您可以在适当的地方破坏旧的对象并在适当的地方构造一个新的对象。(不过,总的来说,这是个坏主意。)
// pointer is destroyed because it goes out of scope,
// but not the object it pointed to. memory leak
if (1) {
Foo *myfoo = new Foo("foo");
}
// pointer is destroyed because it goes out of scope,
// object it points to is deleted. no memory leak
if(1) {
Foo *myfoo = new Foo("foo");
delete myfoo;
}
// no memory leak, object goes out of scope
if(1) {
Foo myfoo("foo");
}
#2
11
Others have already addressed the other issues, so I'll just look at one point: do you ever want to manually delete an object.
其他人已经解决了其他问题,所以我只关注一点:您是否想要手动删除一个对象。
The answer is yes. @DavidSchwartz gave one example, but it's a fairly unusual one. I'll give an example that's under the hood of what a lot of C++ programmers use all the time: std::vector
(and std::deque
, though it's not used quite as much).
答案是肯定的。@DavidSchwartz给出了一个例子,但这是一个很不寻常的例子。我将给出一个例子,这是很多c++程序员一直使用的一个例子:std::vector(和std: deque,虽然没有那么多使用)。
As most people know, std::vector
will allocate a larger block of memory when/if you add more items than its current allocation can hold. When it does this, however, it has a block of memory that's capable of holding more objects than are currently in the vector.
正如大多数人所知道的,当/如果您添加的项超过其当前分配的容量时,std:::vector将分配更大的内存块。然而,当它这样做时,它有一个内存块,它可以容纳比当前向量中更多的对象。
To manage that, what vector
does under the covers is allocate raw memory via the Allocator
object (which, unless you specify otherwise, means it uses ::operator new
). Then, when you use (for example) push_back
to add an item to the vector
, internally the vector uses a placement new
to create an item in the (previously) unused part of its memory space.
为了管理这一点,在覆盖层下的向量是通过分配器对象来分配原始内存(除非你指定否则,这意味着它使用::new)。然后,当您使用(例如)push_back向向量添加一个项时,在内部,向量使用一个新的位置在(先前)未使用的内存空间中创建一个项。
Now, what happens when/if you erase
an item from the vector? It can't just use delete
-- that would release its entire block of memory; it needs to destroy one object in that memory without destroying any others, or releasing any of the block of memory it controls (for example, if you erase
5 items from a vector, then immediately push_back
5 more items, it's guaranteed that the vector will not reallocate memory when you do so.
现在,如果你从向量中擦掉一个项会发生什么?它不能只使用delete——这会释放整个内存块;它需要毁灭一个对象在内存不破坏任何其他人,或释放任何的内存块,它控制(例如,如果您删除5项从一个矢量,然后立刻push_back 5项,它是保证矢量不会重新分配内存,当你这样做。
To do that, the vector directly destroys the objects in the memory by explicitly calling the destructor, not by using delete
.
为此,向量直接通过显式地调用析构函数(而不是使用delete)来破坏内存中的对象。
If, perchance, somebody else were to write a container using contiguous storage roughly like a vector
does (or some variant of that, like std::deque
really does), you'd almost certainly want to use the same technique.
如果有人像向量那样使用连续存储来编写容器(或者类似于std::deque),那么您几乎肯定希望使用相同的技术。
Just for example, let's consider how you might write code for a circular ring-buffer.
例如,让我们考虑如何为循环环缓冲区编写代码。
#ifndef CBUFFER_H_INC
#define CBUFFER_H_INC
template <class T>
class circular_buffer {
T *data;
unsigned read_pos;
unsigned write_pos;
unsigned in_use;
const unsigned capacity;
public:
circular_buffer(unsigned size) :
data((T *)operator new(size * sizeof(T))),
read_pos(0),
write_pos(0),
in_use(0),
capacity(size)
{}
void push(T const &t) {
// ensure there's room in buffer:
if (in_use == capacity)
pop();
// construct copy of object in-place into buffer
new(&data[write_pos++]) T(t);
// keep pointer in bounds.
write_pos %= capacity;
++in_use;
}
// return oldest object in queue:
T front() {
return data[read_pos];
}
// remove oldest object from queue:
void pop() {
// destroy the object:
data[read_pos++].~T();
// keep pointer in bounds.
read_pos %= capacity;
--in_use;
}
// release the buffer:
~circular_buffer() { operator delete(data); }
};
#endif
Unlike the standard containers, this uses operator new
and operator delete
directly. For real use, you probably do want to use an allocator class, but for the moment it would do more to distract than contribute (IMO, anyway).
与标准容器不同,它直接使用操作符new和操作符delete。对于真正的用途,您可能确实希望使用分配器类,但是就目前而言,它所做的更多的是分散注意力而不是贡献(无论如何,在IMO上)。
#3
5
- When you create an object with
new
, you are responsible for callingdelete
. When you create an object withmake_shared
, the resultingshared_ptr
is responsible for keeping count and callingdelete
when the use count goes to zero. - 当您用new创建一个对象时,您负责调用delete。当您使用make_shared创建一个对象时,产生的shared_ptr负责在使用计数为0时保持计数并调用delete。
- Going out of scope does mean leaving a block. This is when the destructor is called, assuming that the object was not allocated with
new
(i.e. it is a stack object). - 超出范围意味着离开一个块。这就是调用析构函数时的情况,假设对象没有被分配给new(例如,它是一个堆栈对象)。
- About the only time when you need to call a destructor explicitly is when you allocate the object with a placement
new
. - 在您需要显式地调用析构函数时,只有当您将对象分配到新位置时。
#4
3
1) Objects are not created 'via pointers'. There is a pointer that is assigned to any object you 'new'. Assuming this is what you mean, if you call 'delete' on the pointer, it will actually delete (and call the destructor on) the object the pointer dereferences. If you assign the pointer to another object there will be a memory leak; nothing in C++ will collect your garbage for you.
1)对象不是通过指针创建的。有一个指针被分配给任何你“新”的对象。假设这是您的意思,如果您在指针上调用“delete”,它实际上会删除(并调用析构函数)对象的指针去引用。如果将指针分配给另一个对象,则会出现内存泄漏;c++里没有东西会帮你收集垃圾。
2) These are two separate questions. A variable goes out of scope when the stack frame it's declared in is popped off the stack. Usually this is when you leave a block. Objects in a heap never go out of scope, though their pointers on the stack may. Nothing in particular guarantees that a destructor of an object in a linked list will be called.
这是两个独立的问题。当在堆栈中声明的堆栈帧从堆栈中弹出时,变量就会超出作用域。通常这是你离开一个街区的时候。堆中的对象永远不会超出范围,尽管堆栈上的指针可能会超出范围。没有什么特别保证会调用链表中对象的析构函数。
3) Not really. There may be Deep Magic that would suggest otherwise, but typically you want to match up your 'new' keywords with your 'delete' keywords, and put everything in your destructor necessary to make sure it properly cleans itself up. If you don't do this, be sure to comment the destructor with specific instructions to anyone using the class on how they should clean up that object's resources manually.
3)没有。可能会有一些深层次的魔力,但通常情况下,你想要把“新的”关键字和“删除”关键字匹配起来,并把所有必要的东西都放到析构函数中,以确保它能正确地清理自己。如果您不这样做,请确保对使用该类的任何使用该类的人员使用特定的指令对其进行注释,以手动清理该对象的资源。
#5
3
To give a detailed answer to question 3: yes, there are (rare) occasions when you might call the destructor explicitly, in particular as the counterpart to a placement new, as dasblinkenlight observes.
对于问题3给出一个详细的答案:是的,有(很少的)情况,你可以明确地调用析构函数,特别是作为一个新的位置,正如dasblinkenlight所观察到的。
To give a concrete example of this:
举一个具体的例子:
#include <iostream>
#include <new>
struct Foo
{
Foo(int i_) : i(i_) {}
int i;
};
int main()
{
// Allocate a chunk of memory large enough to hold 5 Foo objects.
int n = 5;
char *chunk = static_cast<char*>(::operator new(sizeof(Foo) * n));
// Use placement new to construct Foo instances at the right places in the chunk.
for(int i=0; i<n; ++i)
{
new (chunk + i*sizeof(Foo)) Foo(i);
}
// Output the contents of each Foo instance and use an explicit destructor call to destroy it.
for(int i=0; i<n; ++i)
{
Foo *foo = reinterpret_cast<Foo*>(chunk + i*sizeof(Foo));
std::cout << foo->i << '\n';
foo->~Foo();
}
// Deallocate the original chunk of memory.
::operator delete(chunk);
return 0;
}
The purpose of this kind of thing is to decouple memory allocation from object construction.
这种方法的目的是将内存分配与对象结构分离开来。
#6
2
-
Pointers -- Regular pointers don't support RAII. Without an explicit
delete
, there will be garbage. Fortunately C++ has auto pointers that handle this for you!指针——常规指针不支持RAII。没有显式删除,就会有垃圾。幸运的是,c++有自动指针为您处理这个!
-
Scope -- Think of when a variable becomes invisible to your program. Usually this is at the end of
{block}
, as you point out.范围——考虑当一个变量对程序不可见时。通常这是在{block}的末尾,正如您所指出的。
-
Manual destruction -- Never attempt this. Just let scope and RAII do the magic for you.
手动销毁——千万不要这样做。让scope和RAII为你施展魔法。
#7
1
Whenever you use "new", that is, attach an address to a pointer, or to say, you claim space on the heap, you need to "delete" it.
1.yes, when you delete something, the destructor is called.
2.When the destructor of the linked list is called, it's objects' destructor is called. But if they are pointers, you need to delete them manually. 3.when the space is claimed by "new".
无论何时使用“new”,也就是说,将一个地址附加到一个指针上,或者说,您在堆上声明了空间,您需要“删除”它。1。是的,当你删除一些东西时,会调用析构函数。2。当链表的析构函数被调用时,它的对象的析构函数被调用。但如果它们是指针,则需要手动删除它们。3所示。当空间被“new”占据时。
#8
0
Yes, a destructor (a.k.a. dtor) is called when an object goes out of scope if it is on the stack or when you call delete
on a pointer to an object.
是的,当一个对象超出范围(如果它在堆栈上)或当你调用指向一个对象的指针delete时,会调用析构函数(又名dtor)。
-
If the pointer is deleted via
delete
then the dtor will be called. If you reassign the pointer without callingdelete
first, you will get a memory leak because the object still exists in memory somewhere. In the latter instance, the dtor is not called.如果通过delete删除指针,则将调用dtor。如果您重新分配指针而不首先调用delete,您将会得到内存泄漏,因为对象仍然存在于内存中的某个地方。在后一个实例中,不调用dtor。
-
A good linked list implementation will call the dtor of all objects in the list when the list is being destroyed (because you either called some method to destory it or it went out of scope itself). This is implementation dependent.
一个好的链表实现会在链表被销毁时调用链表中所有对象的dtor(因为您或者调用了一些方法来销毁它,或者它本身超出了范围)。这是由实现决定的。
-
I doubt it, but I wouldn't be surprised if there is some odd circumstance out there.
我对此表示怀疑,但如果有什么奇怪的情况发生,我也不会感到惊讶。
#9
0
If the object is created not via a pointer(for example,A a1 = A();),the destructor is called when the object is destructed, always when the function where the object lies is finished.for example:
如果对象不是通过指针创建的(例如,a1 = a();),则在对象被析构时调用析构函数,通常是在对象所在的函数完成时。例如:
void func()
{
...
A a1 = A();
...
}//finish
the destructor is called when code is execused to line "finish".
If the object is created via a pointer(for example,A * a2 = new A();),the destructor is called when the pointer is deleted(delete a2;).If the point is not deleted by user explictly or given a new address before deleting it, the memory leak is occured. That is a bug.
In a linked list, if we use std::list<>, we needn't care about the desctructor or memory leak because std::list<> has finished all of these for us. In a linked list written by ourselves, we should write the desctructor and delete the pointer explictly.Otherwise, it will cause memory leak.
We rarely call a destructor manually. It is a function providing for the system.
Sorry for my poor English!
当代码执行为行“finish”时,将调用析构函数。如果通过指针创建对象(例如,* a2 = new a();),则在删除指针时调用析构函数(删除a2;)。如果用户在删除该点之前没有明确地删除它或给它一个新地址,则会发生内存泄漏。这是一个错误。在链表中,如果我们使用std::list<>,我们不需要关心desctructor或内存泄漏,因为std::list<>已经为我们完成了所有这些。在我们自己编写的链表中,我们应该编写desctructor并明确地删除指针。否则,它将导致内存泄漏。我们很少手动调用析构函数。它是一个为系统提供的函数。对不起,我的英语很差!