jno*_*cho 13 c++ delete-operator c++11
在这个问题中,陈述了这个结构防止实例的堆栈分配.
class FS_Only {
~FS_Only() = delete; // disallow stack allocation
};
Run Code Online (Sandbox Code Playgroud)
我的问题是,它如何阻止分配?我理解,无法显式或隐式删除此实例.但我认为,这将分别导致内存泄漏或运行时错误.
编译器是否足够聪明以排除这种情况并引发编译器错误?还有为什么需要这个呢?
Jon*_*Jon 25
当变量的生命周期结束时,需要运行具有自动存储持续时间(即局部变量)的变量的析构函数.如果没有可访问的析构函数,编译器将拒绝编译分配此类变量的代码.
基本上,"堆栈分配"(一种不精确的术语选择)和免费存储分配之间的区别在于,局部变量构造函数/析构函数调用总是成对出现,而使用免费存储分配,您可以构造一个对象而不会破坏它.因此,通过阻止访问析构函数,您的代码使得无法分配类型的局部变量(如果构造函数运行析构函数也必须运行,但没有析构函数,因此程序被拒绝).
Mik*_*our 15
我理解,无法显式或隐式删除此实例.
更重要的是,它不可能摧毁任何实例; 是否删除或其他方式.
声明自动变量(或"堆栈分配",如果您愿意)不仅会导致在程序到达声明点时创建实例; 当程序离开该块时,它也会导致它被销毁.使用已删除的析构函数,无法完成,因此不允许声明.
这也会阻止您声明静态或线程局部变量,因为它还会在程序或线程结束时生成用于销毁变量的代码.
因此,创建其中之一的唯一方法是使用new,一旦完成,就永远无法破坏它.但是,这并不能完全阻止堆栈分配:
char memory[sizeof(FS_Only)] alignas(FS_Only);
FS_Only * not_fs = new (memory) FS_Only;
Run Code Online (Sandbox Code Playgroud)
还有为什么需要这个呢?
在我看来,你不会.强制性内存泄漏是确保对象永远不会在错误的时间被销毁的可怕方法.相反,使用RAII等技术来管理任何需要动态生命周期的对象,确保它们始终具有明确定义的所有者(或共享所有者),负责在使用后删除它们.C++ 11标准库中的智能指针是一个很好的起点.
将析构函数标记为已删除将导致无法销毁该对象.它是在堆栈上还是在堆上并不重要.对象的所有破坏(无论是通过它超出范围,还是通过对它进行自动delete)都会调用析构函数.因为它是处理析构函数调用的编译器,它会注意到它是否被标记为已删除并发出错误.
但是它不允许创建对象,但是当非指针实例在声明它们的范围的末尾被破坏时,编译器将发出错误,实际上不允许创建实例.仍然可以使用动态分配实例new,但需要注意的是它们无法删除,可能导致内存泄漏.
我有两个答案:
\n\n摘自《C++编程语言》:
\n\n\n\n\n你可以\xe2\x80\x99t有一个可以\xe2\x80\x99t被破坏的局部变量(\xc2\xa717.2.2)...
\n
用我自己的话:
\n\n想一想——在堆栈上创建的变量应该在声明它的作用域结束时被删除。
\n\n通过禁止对象的隐式析构函数,您基本上是在告诉编译器“不允许您在作用域末尾删除此对象”。编译器不想冒创建无法销毁的东西的风险(这是对的 - 如果它很大并且会泄漏兆字节的内存怎么办?),因此它拒绝创建它。这让您只有一个选择 - 在免费商店中创建它并手动管理它。
\n\n现在责任是你的了。但请注意,这是错误的代码 - 对象将永远无法被delete删除,即使是手动也是如此。记住——你delete是析构函数!正如其他答案中正确指出的那样,这是强制内存泄漏,应该避免。