基本问题:程序何时在C中调用类的析构函数方法?有人告诉我,每当对象超出范围或受到删除
时都会调用它
更具体的问题:
1)如果对象是通过指针创建的,并且该指针后来被删除或给定一个新的地址来指向,它所指向的对象是否调用其析构函数(假设没有其他东西指向它)?
2) 接下来是问题1,什么定义了对象何时超出范围(与对象何时离开给定的{block}无关)。换句话说,什么时候对链表中的对象调用析构函数?
3) 你想手动调用析构函数吗?
new
创建对象时,您负责调用delete
。当您使用make_shared
创建对象时,生成的shared_ptr
负责保持计数,并在使用计数为零时调用delete
new
(即它是堆栈对象)
new
时
其他人已经解决了其他问题,所以我只看一点:您是否想要手动删除对象。
答案是肯定的@戴维施瓦茨举了一个例子,但这是一个相当不寻常的例子。我将给出一个很多C程序员一直在使用的例子:std::vector
(和std::deque
,尽管使用得不多)。
正如大多数人所知,std::vector
将在添加的项目超过当前分配的容量时分配更大的内存块。然而,当它这样做时,它有一块内存,能够容纳比当前向量中更多的对象。
为了管理这一点,vector
在封面下做的是通过分配器
对象分配原始内存(除非您另有指定,否则这意味着它使用::operator new
)。然后,当您使用(例如)push_back
将项目添加到向量
时,向量在内部使用placement new
在其内存空间(以前)未使用的部分创建项目。
现在,如果从向量中删除一个项目,会发生什么?它不能只使用删除
——这会释放整个内存块;它需要销毁该内存中的一个对象,而不销毁任何其他对象,或者释放它控制的任何内存块(例如,如果从向量中擦除
5项,然后立即
推回
5项,则保证向量在执行此操作时不会重新分配内存。
为此,向量通过显式调用析构函数直接销毁内存中的对象,而不是使用
delete
。
如果有人使用连续存储来编写容器,大概像
向量
那样(或者像std::deque
这样的变体),那么几乎肯定会使用相同的技术。
例如,让我们考虑一下如何为环形缓冲区编写代码。
#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;
}
~circular_buffer() {
// first destroy any content
while (in_use != 0)
pop();
// then release the buffer.
operator delete(data);
}
};
#endif
与标准容器不同,它直接使用
操作员新建
和操作员删除
。在实际使用中,您可能确实希望使用分配器类,但目前它所做的更多的是分散注意力,而不是贡献(无论如何,在我看来)。
1)如果对象是通过指针创建的,并且该指针后来被删除或给定一个新的地址来指向,它所指向的对象是否调用其析构函数(假设没有其他东西指向它)?
这取决于指针的类型。例如,智能指针通常会在删除对象时删除它们。普通指针则不然。当指针指向不同的对象时,情况也是如此。一些智能指针将销毁旧对象,或者在没有更多引用时销毁它。普通指针没有这样的智能。它们只保留一个地址,并允许您通过特定方式对它们指向的对象执行操作。
2) 接下来是问题1,什么定义了对象何时超出范围(与对象何时离开给定的{block}无关)。换句话说,什么时候对链表中的对象调用析构函数?
这取决于链表的实施。典型的集合在被销毁时会销毁其包含的所有对象。
因此,指针的链接列表通常会破坏指针,但不会破坏它们指向的对象。(这可能是正确的。它们可能是其他指针的引用。)然而,一个专门设计用来包含指针的链表可能会自行删除这些对象。
智能指针的链表可以在指针被删除时自动删除对象,或者在它们没有更多引用的情况下这样做。这完全取决于您选择做您想做的事情的部分。
3) 你想手动调用析构函数吗?
当然可以。一个例子是,如果您想用另一个相同类型的对象替换一个对象,但不想释放内存只是为了再次分配它。您可以在原地销毁旧对象并在原地构建一个新对象。(然而,通常这是个坏主意。)
// 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");
}
我有一些类,我可以不使用任何东西构建它,也可以使用。在销毁时,应该调用给定的函数(如果有)。我的问题是,该对象在创建后立即被销毁,并由我的函数返回,该函数在应该调用它之前调用。传递给构造函数的函数只能调用一次。一些示例代码: 程序输出 因此,函数在被调用之前被调用(在int main()的末尾)。 添加移动构造函数和赋值操作符后,一切都按预期工作: 以及程序输出 实际问题:第一次销毁对象以便调用t
问题内容: 嗨,我想知道何时才是使用htmlspecialchars()的适当位置。是在将数据插入数据库之前还是从数据库中检索数据时? 问题答案: 仅在将数据回显为HTML时才应调用此方法。 不要将转义的HTML存储在数据库中;它只会使查询更烦人。 数据库应存储您的实际数据,而不是其HTML表示形式。
问题内容: 我正在为嵌入式Linux系统编写用户应用程序,并且正在使用设备的常用功能,例如打开,关闭,读取,ioctl等。现在,我读到有关EINTR的信息,它表明该功能已被信号中断,但我不确定其中的含义。在我拥有的所有示例程序中,有时都完成了,例如ioctl(),有时没有完成,例如read()。所以,我有点困惑。 何时最好检查EINTR并重复函数调用? 问题答案: 参见sigaction:http
本文向大家介绍什么时候用delegate,什么时候用Notification?相关面试题,主要包含被问及什么时候用delegate,什么时候用Notification?时的应答技巧和注意事项,需要的朋友参考一下 答:delegate针对one-to-one关系,并且reciever可以返回值 给sender,notification 可以针对one-to-one/many/none,recieve
问题内容: 奇怪的是: 似乎或多或少被定义为。通过这种方式很容易产生错误: 一些fname意外地以else块结尾。修复很简单,我们应该改用它,但是从表面上看,这似乎是一种不错的pythonic方式,并且比“正确”的方式更具可读性。 由于字符串是不可变的,所以为什么字符串错误是什么技术细节?什么时候进行身份检查更好,什么时候进行平等检查更好? 问题答案: 据我所知,检查对象身份是否相等。由于没有强制
问题内容: 我了解OOP语言(例如C ++)中的构造函数的概念。但是,我不确定何时在REACT中使用构造函数。我确实了解JavaScript是面向对象的,但是我不确定构造器实际上是在“构造”什么。 呈现子组件时,子组件中是否需要构造函数?例如: 为了简洁起见,我将简短示例。但是,为什么需要构造函数?您是否需要在子组件中使用一个构造函数来构造道具? 我的ES6知识很可能还没有达到标准。 问题答案: