我有一个类,我希望能够设置一个标志,如果它是堆分配的,那么它可以在自己之后正确清理,如果它在堆栈上则不会尝试删除它自己。问题是......我似乎无法同时覆盖new
和构造函数。所以它从我的new
重载开始,设置isHeapAllocated
标志,然后进入我的构造函数,重置标志。
void* String8::operator new(size_t size)
{
String8* string = (String8*)malloc(size);
if(string == null)
Exception("allocation fail : no free memory");
string->isHeapAllocated = true;
return string;
}
String8::String8()
{
isHeapAllocated = false;
}
因此new String8()
设置isHeapAllocated
标志,然后将其重置为false
。有没有办法做到这一点?
答案 0 :(得分:3)
它不会按预期工作:
new运算符返回要给构造函数的单元化内存。
你 - 正确地做String8* string = (String8*)malloc(size);
,但是*string
,在这个阶段还不是String8对象:它只是包含它的内存批量。
所以string->isHeapAllocated = true;
实际上在一个尚未构造的对象(即UB)中设置了一个标志。
承认这一点不会影响操作系统进程,因此程序不会崩溃(你写的内存已经属于你了,毕竟......),之后你会做String8* ptr = new String8;
之类的事情。在返回新的返回值时,将调用String8 :: String8构造函数,并且该成员将根据您在新运算符重载中的操作独立地设置回“false”。
管理C ++对象的惯用方法是让谁分配负责解除分配。 (如果“谁”是堆栈,它只是按照定义那样做。)
答案 1 :(得分:1)
这是一个坏主意,但这是一种不会调用未定义行为的方法。
#include <iostream>
#include <memory>
#include <set>
using namespace std;
class C {
public:
void* operator new(size_t size) {
C* c = static_cast<C*>(::operator new(size));
heap_instances.insert(c);
return c;
}
C() : heap_allocated(heap_instances.find(this) != heap_instances.end()) {}
const bool heap_allocated;
private:
static set<const C*> heap_instances;
};
set<const C*> C::heap_instances;
int main(int argc, char** argv) {
cout << boolalpha;
C stack;
cout << stack.heap_allocated << '\n'; // false
C* heap_nozero = new C;
cout << heap_nozero->heap_allocated << '\n'; // true
delete heap_nozero;
C* heap_zero = new C();
cout << heap_zero->heap_allocated << '\n'; // true
delete heap_zero;
}
当您完成指针时,可以从heap_instances
删除指针,当然,如果您在多线程环境中运行,则使用更合适的容器。但同样,我不建议您实际执行此操作 - 基于分配的决定行为不是对象应该做的事情。
我能想到的唯一正当理由是启用delete this
。虽然如果你在对象自杀后小心不要访问成员,这是安全的,但让对象管理其他对象的生命周期通常更为安全。
答案 2 :(得分:0)
请注意,如果construtor在堆栈或堆上分配,则会调用construtor,并且对象无法检测它是在堆栈上还是在堆中分配。
要在堆栈中创建对象,请不要使用任何内存分配函数,例如
String8 myString;
要在堆上创建
String8 *myString = new String8();
请注意,在不再使用该对象后,您必须手动进行清理。
对于绑定到堆栈范围的Heap对象的使用,您可以查看由c ++程序强烈使用的RAII原则(请参阅here以更好地解释堆分配和堆栈分配的差异)。 / p>
答案 3 :(得分:0)
不确定为什么你需要这个,真的。调用者有责任在需要时调用delete
,并且无论是在栈上还是在堆上调用对象,你的类的析构函数都不应该是不同的......但是,也许,你正在做一些特殊目的类...这里是我的快速接受。
编辑:您可能也应该向您的班级添加自定义delete
运算符,除非您知道全局delete
调用与您在自定义{{1}中使用的分配函数匹配的释放函数运算符。
new
输出:
#include <cstdlib>
#include <iostream>
namespace so
{
class _test_
{
private:
static bool flag_allocation_heap;
bool flag_heap;
public:
_test_()
: flag_heap( flag_allocation_heap )
{
flag_allocation_heap = 0;
std::cout << flag_heap << std::endl;
}
void * operator new( std::size_t _size )
{
_test_ * test_ = static_cast< _test_ * >( std::malloc( _size ) );
flag_allocation_heap = 1;
return ( test_ );
}
};
bool _test_::flag_allocation_heap = 0;
} // namespace so
int main()
{
so::_test_ test_stack_;
so::_test_ * test_memory_ = new so::_test_;
delete test_memory_;
return( 0 );
}