是否允许删除这个;如果删除语句是将在该类实例上执行的最后一条语句?当然,我确定this指针所表示的对象是新创建的。

我在想这样的事情:

void SomeModule::doStuff()
{
    // in the controller, "this" object of SomeModule is the "current module"
    // now, if I want to switch over to a new Module, eg:

    controller->setWorkingModule(new OtherModule());

    // since the new "OtherModule" object will take the lead, 
    // I want to get rid of this "SomeModule" object:

    delete this;
}

我能这样做吗?


当前回答

这是引用计数对象的核心习惯用法。

引用计数是一种强大的确定性垃圾收集形式——它确保对象管理自己的生命周期,而不是依赖“智能”指针等来为它们做这些。底层对象只能通过“Reference”智能指针访问,设计为指针在实际对象中递增或递减一个成员整数(引用计数)。

当最后一个引用退出堆栈或被删除时,引用计数将归零。对象的默认行为将是调用“delete this”来进行垃圾收集——我写的库在基类中提供了一个受保护的虚拟“CountIsZero”调用,这样你就可以为缓存之类的事情覆盖这个行为。

确保安全的关键是不允许用户访问相关对象的构造函数(使其受保护),而是让他们调用一些静态成员——FACTORY——比如“static Reference CreateT(…)”。通过这种方式,你可以确定它们总是用普通的“new”构建的,并且没有原始指针可用,所以“delete this”永远不会爆炸。

其他回答

One of the reasons that C++ was designed was to make it easy to reuse code. In general, C++ should be written so that it works whether the class is instantiated on the heap, in an array, or on the stack. "Delete this" is a very bad coding practice because it will only work if a single instance is defined on the heap; and there had better not be another delete statement, which is typically used by most developers to clean up the heap. Doing this also assumes that no maintenance programmer in the future will cure a falsely perceived memory leak by adding a delete statement.

Even if you know in advance that your current plan is to only allocate a single instance on the heap, what if some happy-go-lucky developer comes along in the future and decides to create an instance on the stack? Or, what if he cuts and pastes certain portions of the class to a new class that he intends to use on the stack? When the code reaches "delete this" it will go off and delete it, but then when the object goes out of scope, it will call the destructor. The destructor will then try to delete it again and then you are hosed. In the past, doing something like this would screw up not only the program but the operating system and the computer would need to be rebooted. In any case, this is highly NOT recommended and should almost always be avoided. I would have to be desperate, seriously plastered, or really hate the company I worked for to write code that did this.

这是一个老问题,但@Alexandre问“为什么有人想这样做?”,我想我可以提供一个示例用法,我今天下午正在考虑。

遗留代码。使用裸指针Obj* Obj,并在末尾使用delete Obj。

不幸的是,我有时需要,而不是经常,让对象活得更久。

我正在考虑使它成为一个引用计数智能指针。但会有很多代码要改变,如果我是使用ref_cnt_ptr<Obj>无处不在。如果你混合裸Obj*和ref_cnt_ptr,当最后一个ref_cnt_ptr消失时,你可以隐式删除对象,即使Obj*仍然存在。

因此,我正在考虑创建一个explicit_delete_ref_cnt_ptr。例如,一个引用计数指针,其中删除只在显式删除例程中完成。在现有代码知道对象的生命周期的地方使用它,以及在我的新代码中使用它,使对象的生存时间更长。

在操作explicit_delete_ref_cnt_ptr时增加或减少引用计数。

但当在explicit_delete_ref_cnt_ptr析构函数中看到引用计数为零时,则不释放。

仅当在显式删除类操作中看到引用计数为零时才释放。例如:

template<typename T> class explicit_delete_ref_cnt_ptr { 
 private: 
   T* ptr;
   int rc;
   ...
 public: 
   void delete_if_rc0() {
      if( this->ptr ) {
        this->rc--;
        if( this->rc == 0 ) {
           delete this->ptr;
        }
        this->ptr = 0;
      }
    }
 };

好吧,就像这样。引用计数指针类型不会自动删除rc'ed ptr析构函数中所指向的对象,这有点不寻常。但这似乎可以使混合裸指针和rc'ed指针更安全一些。

但到目前为止还不需要删除这个。

但后来我想到:如果被指向的对象,被指针,知道它被引用计数,例如,如果计数在对象内部(或在其他一些表中),那么例程delete_if_rc0可能是被指针对象的一个方法,而不是(智能)指针。

class Pointee { 
 private: 
   int rc;
   ...
 public: 
   void delete_if_rc0() {
        this->rc--;
        if( this->rc == 0 ) {
           delete this;
        }
      }
    }
 };

实际上,它根本不需要是一个成员方法,但可以是一个自由函数:

map<void*,int> keepalive_map;
template<typename T>
void delete_if_rc0(T*ptr) {
        void* tptr = (void*)ptr;
        if( keepalive_map[tptr] == 1 ) {
           delete ptr;
        }
};

(顺便说一句,我知道代码不太正确-如果我添加所有的细节,它变得不那么可读,所以我就这样留下它。)

只要对象在堆中,删除是合法的。 您需要要求对象仅为堆。 做到这一点的唯一方法是使析构函数受保护——这种方法可以从类中only调用delete,因此您需要一个方法来确保删除

c++ FAQ Lite中有一个专门的条目

https://isocpp.org/wiki/faq/freestore-mgmt#delete-this

我认为这句话很好地总结了这一点

只要你小心,对象自杀是可以的(删除这个)。

如果你害怕,有一个完全合法的破解方法:

void myclass::delete_me()
{
    std::unique_ptr<myclass> bye_bye(this);
}

我认为删除它是c++的惯用方法,我只是把它作为一种好奇来展示。

在某些情况下,这个构造实际上是有用的——您可以在抛出需要该对象成员数据的异常后删除该对象。对象在发生抛出之前一直有效。

void myclass::throw_error()
{
    std::unique_ptr<myclass> bye_bye(this);
    throw std::runtime_exception(this->error_msg);
}

注意:如果你使用的是c++ 11之前的编译器,你可以使用std::auto_ptr而不是std::unique_ptr,它会做同样的事情。