【发布时间】:2015-10-01 21:28:51
【问题描述】:
给定一个类层次结构:
class A {
private:
string * p_str;
public:
A() : p_str(new string())
{
}
virtual ~A() {
delete p_str;
}
};
class B : public A {
public:
B() {
}
virtual ~B() override {
}
virtual void Test() {
cout << "B::Test()" << endl;
}
};
int main(int, char**)
{
B b;
b.Test();
return 0;
}
有一个p_str 指向字符串的指针(不管它指向什么对象)。
把它换成std::unique_ptr除了不写delete p_str有什么好处吗?
class A {
private:
std::unique_ptr<string> p_str;
public:
A() : p_str(make_unique<string>())
virtual ~A() {}
}
?如果任何派生类的构造函数抛出异常,任何代码变体都会发生内存泄漏。
UPD我试过这个代码:
包括
#include <memory>
using namespace std;
class Pointed {
public:
Pointed() { std::cout << "Pointed()\n"; }
~Pointed() { std::cout << "~Pointed()\n"; }
};
class A1 {
private:
Pointed * p_str;
public:
A1() : p_str(new Pointed()) {
cout << "A1()\n";
throw "A1 constructor";
}
virtual ~A1() {
cout << "~A1()\n";
delete p_str;
}
};
class B1 : public A1 {
public:
B1() {
throw "B constructor";
}
virtual ~B1() override {
cout << "~B1()\n";
}
virtual void Test() {
cout << "B1::Test()" << endl;
}
};
class A2 {
private:
std::unique_ptr<Pointed> p_str;
public:
A2() : p_str(make_unique<Pointed>()) {
cout << "A2()\n";
throw "A2 constructor";
}
virtual ~A2() {
cout << "~A2()\n";
}
};
class B2 : public A2 {
public:
B2() {
cout << "B2()\n";
throw "B2 constructor";
}
virtual ~B2() override {
cout << "~B2()\n";
}
virtual void Test() {
cout << "B2::Test()" << endl;
}
};
int main(int, char**) {
cout << "B1::A1 (raw pointers)\n";
try {
B1 b1;
}
catch (...) {
cout << "Exception thrown for B1\n";
}
cout << "\nB2::A2 (unique pointers)\n";
try {
B2 b2;
}
catch (...) {
cout << "Exception thrown for b2\n";
}
cin.get();
return 0;
}
输出是:
B1::A1 (raw pointers)
Pointed()
A1()
Exception thrown for B1
B2::A2 (unique pointers)
Pointed()
A2()
~Pointed()
Exception thrown for b2
所以,结果是unique_ptr在声明成员的同一个类的构造函数中发生异常时被自动删除。
【问题讨论】:
-
"如果任何派生类的构造函数抛出异常,任何代码变体都会发生内存泄漏。"你确定吗?在我看来就像won't be a leak regardless。由于是子对象在构造函数中抛出异常,所以抛出异常时会调用基对象的析构函数。
-
@jaggedSpire 对“任何派生”感到抱歉,但如果在定义成员的类的构造函数中发生异常,则会出现内存泄漏:coliru.stacked-crooked.com/a/3bd94aa1c8fbb7df
-
这是正确的,但不是您最初断言的。请记住要小心措辞——当涉及到异常时,您抛出的 where 有时会产生重大影响。由于您修复了您的声明,因此它不会说如果继承类抛出异常就会发生内存泄漏,我愿意删除我原来的评论。
-
@jaggedSpire 请不要!让所有讨论留在这里,以供未来读者理解
标签: c++ pointers c++11 memory-leaks unique-ptr