簡體   English   中英

如何在構造函數中銷毀對象並返回 NULL

[英]How do you destroy an object in its constructor and return NULL

我正在嘗試編寫一個必須檢查正確初始化的 cpp 模塊。 它需要用至少一個非空指針初始化。 如果不是,它需要刪除自己並返回NULL。 下面的程序似乎確實破壞了對象,但它似乎沒有返回 null。

這里發生了什么?

#include <iostream>

using namespace std;

class cmod {
public:
        cmod(int *p1=NULL, int *p2=NULL)
        {
                if( p1 == NULL && p2 == NULL){
                        delete(this);
                }
                else
                        cout << __func__ << ": Initialized" << endl;
                if(p1 != NULL)
                        cout << "*p1 = " << *p1 << endl;
                if(p2 !=NULL)
                        cout << "*p2 = " << *p2 << endl;
        }
        ~cmod()
        {
                cout << __func__ << ": Destroyed" << endl;
        }

};

int main()
{
        int a=10, b = 20;
        cmod *p = new cmod();
        if(p == NULL)
                cout << __func__ << ": Unable to initialize" << endl;
        cmod *p1 = new cmod(&a, &b);
}

以下是輸出:

~cmod: Destroyed
cmod: Initialized
*p1 = 10
*p2 = 2

為什么行Unable to initialize不打印?

更新:查看所有答案后,我想出了以下內容:

#include <iostream>

using namespace std;

class cmod {
private:
        int *l1,*l2;
        cmod()
        {
                throw std::runtime_error("Failed to construct object.   No arguements");
        }
        cmod(int *p1=NULL, int *p2=NULL)
        {
                if( p1 == NULL && p2 == NULL){
                        throw std::runtime_error("Failed to construct object. Both args NULL");
                }
                else
                        cout << __func__ << ": Initialized" << endl;
                if(p1 != NULL)
                        l1 = p1;
                if(p2 !=NULL)
                        l2 = p2;
        }
        ~cmod()
        {
                cout << __func__ << ": Destroyed" << endl;
        }
public:
        static cmod * initialize(int *p1=NULL, int *p2 = NULL)
        {
                if( p1 == NULL && p2 == NULL){
                        return NULL;
                }
                else
                        return new cmod(p1,p2);

        }
        void dump()
        {
                cout << __func__ << ": a = " << *l1 << endl;
                cout << __func__ << ": b = " << *l2 << endl;

        }
int main()
{
        int a=10, b = 20;
        cmod *p = cmod::initialize(NULL, NULL);
        if(p == NULL)
                cout << __func__ << ": Unable to initialize" << endl;
        cmod *p1 = cmod::initialize(&a, &b);
        if(p!=NULL)
                p->dump();
        if(p1!=NULL)
                p1->dump();
}

現在這是一個正確的方法嗎?

構造函數將始終返回其類的對象,除非它拋出異常。 所以你想要做的是:

cmod(int *p1=NULL, int *p2=NULL)
{
    if( p1 == NULL && p2 == NULL)
        throw std::runtime_error("Failed to construct object.");
}

你不能delete this 考慮在以下場景中會發生什么:

cmod A;  // default constructor: called with both arguments NULL

A不在堆上分配,而是在堆棧上時。 但是用一個不是由new分配的指針調用delete是一個錯誤的程序(如果你幸運的話它會在運行時崩潰)。

正如 Harald 指出的那樣,處理構造函數的錯誤輸入適當且正確的方法是 throw 和 exception 使用工廠並不完全合適,因為用戶可能仍會嘗試通過其他方式構造對象(除非通過將工廠設為friend並且將構造函數設為privateprotected來禁止這樣做)。

如果要在構造對象之前驗證輸入,最好使用static成員函數來執行此操作,而不是在構造函數中驗證輸入。 此外,將構造函數設為private以防止意外誤用。

class cmod {

   public:

      static cmod* buildInstance(int *p1=NULL, int *p2=NULL)
      {
         if( p1 == NULL && p2 == NULL){
            return NULL;
         }
         else {
            return new cmd(p1, p2);
         }
      }

      ~cmod()
      {
         cout << __func__ << ": Destroyed" << endl;
      }

   private:

      cmod(int *p1, int *p2)
      {
         cout << __func__ << ": Initialized" << endl;
         if(p1 != NULL)
            cout << "*p1 = " << *p1 << endl;
         if(p2 !=NULL)
            cout << "*p2 = " << *p2 << endl;
      }

};

然后將其用作:

int main()
{
   int a=10, b = 20;
   cmod *p = mod::buildInstance();
   if(p == NULL)
      cout << __func__ << ": Unable to initialize" << endl;
   cmod *p1 = cmod::buildInstance(&a, &b);
}

您需要使用工廠模式來創建對象,以便將對象創建委托給工廠。 通過這種方式工廠可以控制是否應該創建對象。

所以創建另一個名為 cmodFactory 的類,它有一個返回 cmod 的靜態方法。 在這個靜態方法中,您可以檢查是否要創建對象並相應地返回。

添加示例代碼:

 #include <iostream>

using namespace std;

class cmod {
public:
        cmod(int *p1=NULL, int *p2=NULL)
        {
                cout << __func__ << ": Initialized" << endl;
                if(p1 != NULL)
                        cout << "*p1 = " << *p1 << endl;
                if(p2 !=NULL)
                        cout << "*p2 = " << *p2 << endl;
        }
        ~cmod()
        {
                cout << __func__ << ": Destroyed" << endl;
        }

};

class cmodFactory {
public:
        static cmod * getCmodInstance(int *p1=NULL, int *p2=NULL)
        {
                if( p1 == NULL && p2 == NULL){
                       return NULL;
                }
                else
                {
                  cmod * instance = new cmod(p1, p2);
                  return instance;
                }
        }

};

int main()
{
        int a=10, b = 20;
        cmod *p = cmodFactory::getCmodInstance();
        if(p == NULL)
                cout << __func__ << ": Unable to initialize" << endl;
       p = cmodFactory::getCmodInstance(&a, &b);

        if(p == NULL)
                cout << __func__ << ": Unable to initialize" << endl;
        else 
          cout << __func__ << ": initialized" << endl;


}

輸出是

main: Unable to initialize
cmod: Initialized
*p1 = 10
*p2 = 20
main: initialized

構造函數不能返回 null。 構造函數不返回指針。 在構造函數中調用delete(this)是各種錯誤。

有一種方法可以取消對象的構造:拋出異常。 但是,在這種情況下,新表達式不會返回 null。 事實上,它根本不會返回。 相反,您必須捕獲異常才能處理這種情況。

為什么“無法初始化不打印?

因為除非使用非拋出變量並且分配(與對象的初始化分開)失敗,否則 new 表達式永遠不會返回 null。 在這種情況下,分配沒有失敗,並且使用了拋出變量(默認)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM