dav*_*vka 4 c++ operator-overloading reference-counting
我正在尝试重载operator delete,这样我就可以返回一个普通的指针,指向那些不希望使用智能指针的人,并且能够控制删除对象的时间.
我定义了一个由几个灵魂构造的类Cat,有一个重载的操作符删除,什么都不做,以及析构函数减少了灵魂的数量(并且还做了一些吹牛).当灵魂达到0时,析构函数调用global :: delete,然后cat死掉.
这听起来很简单,但不能按预期工作.这是代码:
class Cat {
public:
Cat(string n): name(n), souls(9)
{ cout << "Myaou... " << name << " is born\n"; }
~Cat();
void operator delete(void *p) { cout << "!!! operator delete called\n"; }
void report()
{ cout << name << "'s here, " << souls << " souls to spend\n"; }
friend ostream& operator<< (const ostream& o, const Cat& cat);
private:
void kill();
const string name;
int souls;
};
Cat::~Cat()
{
cout << "!!! dtor called\n";
kill();
}
void Cat::kill()
{
if (--souls)
cout << name << " is still alive! I have " << souls << " souls left.\n";
else {
cout << name << " is dying... good bye world!\n";
::delete((void*)this);
}
}
ostream& operator<< (const ostream& o, const Cat& cat)
{
return o << cat.name << "'s here, " << cat.souls << " souls to spend\n";
}
Run Code Online (Sandbox Code Playgroud)
这里是主要的:
int main()
{
Cat *p = new Cat("Mitzi");
for (;;)
{
char c[100];
// cout << *p;
p->report();
cout << "come on, hit me!";
cin >> c;
delete p;
}
}
Run Code Online (Sandbox Code Playgroud)
我希望循环会运行9次,然后会发生令人不快(崩溃)的事情.但是,这是输出:
Myaou... Mitzi is born
Mitzi's here, 9 souls to spend
come on, hit me!c
!!! dtor called
Mitzi is still alive! I have 8 souls left.
!!! operator delete called
's here, 8 souls to spend
come on, hit me!c
!!! dtor called
is still alive! I have 7 souls left.
*** glibc detected *** /home/davidk/workspace/string_test/Debug/string_test: double free or corruption (fasttop): 0x080cd008 ***
Run Code Online (Sandbox Code Playgroud)
似乎在第一次删除后,名称成员被销毁,下一次删除导致崩溃.有什么解释吗?我在Linux上用gcc编译,可能是一个编译器bug?
顺便说一句,当我在cout <<*p而不是repotr()中使用运算符<<()时,它也很奇怪:它进入了一个从运算符<<()中调用构造函数的无限循环.这里发生了什么?:)
谢谢!
sha*_*oth 19
您已经误用了每个C++概念,这会导致错误.当delete p;第一次调用时,C++调用Cat::~Cat()析构函数,该析构函数隐式销毁std::string实体内部.当delete p;被调用时,第二次Cat::~Cat()重新运行并重新运行析构函数,std::string这会导致未定义的行为导致程序崩溃,因为我认为std::string::~string()不会使指向缓冲区的指针无效,因此当std::string::~string()尝试使用相同的第二次释放缓冲区时解决这个导致着名的双重免费.
操作员delete调用对象析构函数,之后你就没有人的土地了.正如其他人指出的那样,你想做的事情是不可能的.
当在堆上和堆栈上构造对象时,您正在做的事情也有点不协调.
delete根据一些内部逻辑(生命数量达到9),如果使用new构造,你的想法是覆盖操作符,对象将保持活跃状态.
当在堆栈(Cat cat("Chesire cat");)上构造时,对象在超出范围时将始终被破坏.为了实现你想要做的事情,你还需要将析构函数的行为改为"停止破坏".这是不可能的,也是有充分理由的.
因此,如果您想要重新计算,只需实现自己的机制.毕竟,如果你至少没有完成自己的引用计数内存管理,你不能称自己为C++程序员:))