1. 程式人生 > >關於GCC編譯程式報出警告:note: neither the destructor nor the class-specific operator delete will be called...的問題及解決方案

關於GCC編譯程式報出警告:note: neither the destructor nor the class-specific operator delete will be called...的問題及解決方案

在任意Linux系統,GCC 4.1.1或4.1.2環境下,建立以下工程:

Makefile

test: test.o agg.o
    g++ -o test test.o agg.o

agg.o: agg.cpp agg.h base.h
    g++ -g -c -Wall -o agg.o agg.cpp

test.o: test.cpp agg.h base.h
    g++ -g -c -Wall -o test.o test.cpp

test.cpp

#include "agg.h"

int main(int, char**)
{
    CAggretive obj;
    return 0;
}

base.h

#include <stdio.h>

class CBase
{
public:
    CBase() { printf("CBase/n"); }
    ~CBase() { printf("~CBase/n"); }
};

agg.h

#include <memory>

class CBase;

class CAggretive
{
public:
    CAggretive();
    ~CAggretive() { printf("~CAggretive/n"); }
private:
    std::auto_ptr<CBase>    m_obj;
};

agg.cpp

#include "agg.h"
#include "base.h"

CAggretive::CAggretive()  : m_obj(new CBase())
{
    printf("CAggretive/n");
};

編譯後得到目標可執行檔案test。編譯時得到警告資訊:

g++ -g -c -Wall -o test.o test.cpp
/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/memory: In destructor ‘std::auto_ptr<_Tp>::~auto_ptr() [with _Tp = CBase]’:
agg.h:9:   instantiated from here
/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/memory:259: warning: possible problem detected in invocation of delete operator:
/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/memory:259: warning: invalid use of undefined type ‘struct CBase’
agg.h:3: warning: forward declaration of ‘struct CBase’
/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/memory:259: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.
g++ -o test test.o agg.o
執行可執行檔案test,程式輸出:

CBase
CAggretive
~CAggretive
可以發現CBase的解構函式沒有被呼叫,在實際應用中將造成記憶體和資源洩漏。

這是因為編譯test.cpp時,包含檔案樹中沒有base.h,所以編譯器在實體化auto_ptr<CBase>類時不知道如何執行delete CBase型資料結構的方法。

在test.cpp最開頭加上一句#include "base.h"即可解決此問題。編譯agg.cpp時沒有給出警告便是此原因。

(那麼,為什麼編譯器知道如何new CBase型資料結構呢?那是因為CAggretive的建構函式是寫在agg.cpp中,因此它的實現在agg.o中已經編譯進去了)

因為像agg.h這樣前置宣告CBase,然後在類成員中使用它是一種不好的習慣,任何沒有包含base.h而直接使用agg.h的cpp檔案在編譯時都會產生洩漏。

實際應用中可能會出現比本例更為複雜的引用情況,修改方式可能不那麼簡單。但總體思路是一樣的,即是讓編譯器在編譯此檔案時確實包含用作auto_ptr的模板引數的類。