是否允许删除这个;如果删除语句是将在该类实例上执行的最后一条语句?当然,我确定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;
}

我能这样做吗?


当前回答

Yes, delete this; has defined results, as long as (as you've noted) you assure the object was allocated dynamically, and (of course) never attempt to use the object after it's destroyed. Over the years, many questions have been asked about what the standard says specifically about delete this;, as opposed to deleting some other pointer. The answer to that is fairly short and simple: it doesn't say much of anything. It just says that delete's operand must be an expression that designates a pointer to an object, or an array of objects. It goes into quite a bit of detail about things like how it figures out what (if any) deallocation function to call to release the memory, but the entire section on delete (§[expr.delete]) doesn't mention delete this; specifically at all. The section on destructors does mention delete this in one place (§[class.dtor]/13):

在定义虚析构函数时(包括隐式定义(15.8)),非数组释放函数的确定就像表达式delete this出现在析构函数类的非虚析构函数中一样(参见8.3.5)。

这倾向于支持标准考虑删除这个的想法;如果它是无效的,它的类型就没有意义。这是标准中唯一提到删除的地方;据我所知,根本没有。

不管怎样,有些人认为删除这条消息是一种恶意攻击,并告诉任何愿意听的人应该避免这样做。一个经常被引用的问题是很难确保类的对象只被动态分配。其他人认为这是一个非常合理的习语,并一直在使用它。就我个人而言,我介于两者之间:我很少使用它,但当它似乎是适合这项工作的工具时,不要犹豫。

The primary time you use this technique is with an object that has a life that's almost entirely its own. One example James Kanze has cited was a billing/tracking system he worked on for a phone company. When you start to make a phone call, something takes note of that and creates a phone_call object. From that point onward, the phone_call object handles the details of the phone call (making a connection when you dial, adding an entry to the database to say when the call started, possibly connect more people if you do a conference call, etc.) When the last people on the call hang up, the phone_call object does its final book-keeping (e.g., adds an entry to the database to say when you hung up, so they can compute how long your call was) and then destroys itself. The lifetime of the phone_call object is based on when the first person starts the call and when the last people leave the call -- from the viewpoint of the rest of the system, it's basically entirely arbitrary, so you can't tie it to any lexical scope in the code, or anything on that order.

对于任何可能关心这种编码的可靠性的人来说:如果你打电话到欧洲的任何地方,从欧洲的任何地方,或通过欧洲的任何地方,很有可能它是由代码处理的(至少是部分)。

其他回答

这是一个老问题,但@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,因此您需要一个方法来确保删除

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

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,它会做同样的事情。

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

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

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

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

Yes, delete this; has defined results, as long as (as you've noted) you assure the object was allocated dynamically, and (of course) never attempt to use the object after it's destroyed. Over the years, many questions have been asked about what the standard says specifically about delete this;, as opposed to deleting some other pointer. The answer to that is fairly short and simple: it doesn't say much of anything. It just says that delete's operand must be an expression that designates a pointer to an object, or an array of objects. It goes into quite a bit of detail about things like how it figures out what (if any) deallocation function to call to release the memory, but the entire section on delete (§[expr.delete]) doesn't mention delete this; specifically at all. The section on destructors does mention delete this in one place (§[class.dtor]/13):

在定义虚析构函数时(包括隐式定义(15.8)),非数组释放函数的确定就像表达式delete this出现在析构函数类的非虚析构函数中一样(参见8.3.5)。

这倾向于支持标准考虑删除这个的想法;如果它是无效的,它的类型就没有意义。这是标准中唯一提到删除的地方;据我所知,根本没有。

不管怎样,有些人认为删除这条消息是一种恶意攻击,并告诉任何愿意听的人应该避免这样做。一个经常被引用的问题是很难确保类的对象只被动态分配。其他人认为这是一个非常合理的习语,并一直在使用它。就我个人而言,我介于两者之间:我很少使用它,但当它似乎是适合这项工作的工具时,不要犹豫。

The primary time you use this technique is with an object that has a life that's almost entirely its own. One example James Kanze has cited was a billing/tracking system he worked on for a phone company. When you start to make a phone call, something takes note of that and creates a phone_call object. From that point onward, the phone_call object handles the details of the phone call (making a connection when you dial, adding an entry to the database to say when the call started, possibly connect more people if you do a conference call, etc.) When the last people on the call hang up, the phone_call object does its final book-keeping (e.g., adds an entry to the database to say when you hung up, so they can compute how long your call was) and then destroys itself. The lifetime of the phone_call object is based on when the first person starts the call and when the last people leave the call -- from the viewpoint of the rest of the system, it's basically entirely arbitrary, so you can't tie it to any lexical scope in the code, or anything on that order.

对于任何可能关心这种编码的可靠性的人来说:如果你打电话到欧洲的任何地方,从欧洲的任何地方,或通过欧洲的任何地方,很有可能它是由代码处理的(至少是部分)。