以下代碼test-templated-destructor.cpp
複製了我正在使用的庫的組織結構。我使用的是:在非模板類析構函數中刪除模板類指針?
$ cat /etc/issue
Ubuntu 14.04.5 LTS \n \l
$ g++ --version
g++ (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
$ g++ -std=c++14
g++: error: unrecognized command line option ‘-std=c++14’
g++: fatal error: no input files
compilation terminated.
$ g++ -std=c++11
g++: fatal error: no input files
compilation terminated.
有:
- 基類
AA
,並從它BB
和CC
派生類; - 抽象類
AAInstancer
,和類從它AAInstancerTemplated
衍生其是模板化 AAHandler
類,它具有一個模板函數addTemplatedObject
,其存儲AAInstancer*
指針new AAInstancerTemplated<T>()
目的,在上述類- 的
map
場所在main()
,一個AAHandler
對象實例化,並呼籲它.addTemplatedObject<BB>("BB");
如果我運行valgrind
此,它報告:
==21000== 43 (16 direct, 27 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==21000== at 0x4C2B0E0: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21000== by 0x40141B: void AAHandler::addTemplatedObject<BB>(std::string) (test-templated-destructor.cpp:64)
==21000== by 0x40113E: main (test-templated-destructor.cpp:82)
我認爲這個問題是我們在addTemplatedObject()
使用new
,因此,我們應該相應地刪除其最新的程序退出 - 但不這樣做,從而爲泄漏的原因。
因此,我認爲,要編寫通過instancers
地圖循環迭代,並delete
這幫指針在AAHandler
的desctructor,但我不能:
- 如果我寫:
~AAHandler() {
cout << " (running AAHandler destructor)" << endl;
map<string, AAInstancer*>::iterator it;
for (it = instancers.begin(); it != instancers.end(); it++) {
delete it->second;
}
}
...然後我會在編譯:
$ g++ -g -Wall test-templated-destructor.cpp -o test-templated-destructor.exe
test-templated-destructor.cpp: In destructor ‘AAHandler::~AAHandler()’:
test-templated-destructor.cpp:60:18: warning: deleting object of abstract class type ‘AAInstancer’ which has non-virtual destructor will cause undefined behaviour [-Wdelete-non-virtual-dtor]
delete it->second;
^
...這聽起來是對的 - AAInstancer
沒有定義析構函數,所以編譯器可能會自動添加爲非虛擬的,導致此警告(儘管通過valgrind
運行此操作將顯示不再檢測到泄漏)。
- 如果我寫:
template <class T>
~AAHandler() {
cout << " (running AAHandler destructor)" << endl;
map<string, AAInstancer*>::iterator it;
for (it = instancers.begin(); it != instancers.end(); it++) {
delete (AAInstancerTemplated<T>*)it->second;
}
}
...在希望這個析構函數被調用,如果我們叫addTemplatedObject
一些模板(它不會反正),編譯失敗:
$ g++ -g -Wall test-templated-destructor.cpp -o test-templated-destructor.exe && ./test-templated-destructor.exe
test-templated-destructor.cpp:57:14: error: destructor ‘AAHandler::~AAHandler()’ declared as member template
~AAHandler() {
^
...這也是有意義的:AAHandler
是一個非模板類,所以它的析構函數可能不應該被模板化。
那麼,是不是可以寫入AAHandler
析構函數,這將delete
所有new
指針在其instancers
,無論哪個模板,他們實例化 - 用最少的(或最佳,無),更改現有的代碼?
test-templated-destructor.cpp
// g++ -g -Wall test-templated-destructor.cpp -o test-templated-destructor.exe && ./test-templated-destructor.exe
// valgrind --leak-check=yes ./test-templated-destructor.exe
#include <iostream>
#include <map>
using namespace std;
class AA {
public:
string myname;
AA() {
myname = "";
cout << " AA instantiated\n";
}
};
class BB : public AA {
public:
string mystuff;
BB() {
mystuff = "";
cout << " BB instantiated\n";
}
};
class CC : public AA {
public:
string mythings;
CC() {
mythings = "";
cout << " CC instantiated\n";
}
};
class AAInstancer
{
public:
virtual AA* createInstance() = 0;
string tagName;
};
template <class T>
class AAInstancerTemplated: public AAInstancer
{
public:
AA* createInstance() {
return new T();
}
};
class AAHandler
{
public:
~AAHandler() { }
AAHandler() { }
static map<string, AAInstancer*> instancers;
template <class T>
static void addTemplatedObject(string tagName) {
AAInstancer* instancer = new AAInstancerTemplated<T>();
instancer->tagName = tagName;
instancers[tagName] = instancer;
}
AAHandler* get() {
if(singleton == NULL)
singleton = new AAHandler();
return singleton;
}
private:
static AAHandler* singleton;
};
map<string, AAInstancer*> AAHandler::instancers;
int main()
{
AAHandler aah;
aah.addTemplatedObject<BB>("BB");
cout << "Address of aah: " << static_cast<void*>(&aah) << endl;
return 0;
}
爲什麼不使用'的std ::的unique_ptr的''而不是* AAInstancer'? –
user0042
如何'地圖<字符串的unique_ptr>'那麼你就不必做什麼? –
CoryKramer