重载运算符删除,或者如何杀死一只猫?

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()尝试使用相同的第二次释放缓冲区时解决这个导致着名的双重免费.

  • 每个c ++概念都可能,对吧? (4认同)

Igo*_*aka 7

操作员delete调用对象析构函数,之后你就没有人的土地了.正如其他人指出的那样,你想做的事情是不可能的.

当在堆上和堆栈上构造对象时,您正在做的事情也有点不协调.

delete根据一些内部逻辑(生命数量达到9),如果使用new构造,你的想法是覆盖操作符,对象将保持活跃状态​​.

当在堆栈(Cat cat("Chesire cat");)上构造时,对象在超出范围时将始终被破坏.为了实现你想要做的事情,你还需要将析构函数的行为改为"停止破坏".这是不可能的,也是有充分理由的.

因此,如果您想要重新计算,只需实现自己的机制.毕竟,如果你至少没有完成自己的引用计数内存管理,你不能称自己为C++程序员:))