智能指针 (unique_ptr) 而不是原始指针作为 class 成员
Smart pointer (unique_ptr) instead of raw pointer as class member
给定 class 层次结构:
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() {}
}
?如果任何派生的构造函数 class 抛出异常,则任何代码变体都会发生内存泄漏。
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
因此,结果是当在声明成员的同一个 class 的构造函数中发生异常时,unique_ptr
被自动删除。
使用原始指针,您可以进行双重删除,因为您没有手动实现的复制 c-tor 和赋值运算符。
A a;
A b = a; // b.p_str store the same address, that a.p_str
使用 unique_ptr
你不能 copy/assign 对象,但你可以移动它,而不用写移动 c-tor/move 赋值运算符。
A a;
A b = a; // cannot do this, since `unique_ptr` has no copy constructor.
A b = std::move(a); // all is okay, now `b` stores `unique_ptr` with data and `a` stores `nullptr`
但实际上,我不知道为什么你应该在这里存储指针,而不仅仅是 std::string
类型的对象,这是你的示例中的最佳解决方案。
除了 ForEveR 的回复,使用 unique_ptr
告诉 reader 只有一个对象 指代(在本例中,拥有)那个字符串。使用裸指针,无论谁正在阅读您的代码,都不知道有多少其他对象、局部变量或其他任何东西(单例?全局变量?)访问 and/or 修改该字符串。
给定 class 层次结构:
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() {}
}
?如果任何派生的构造函数 class 抛出异常,则任何代码变体都会发生内存泄漏。
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
因此,结果是当在声明成员的同一个 class 的构造函数中发生异常时,unique_ptr
被自动删除。
使用原始指针,您可以进行双重删除,因为您没有手动实现的复制 c-tor 和赋值运算符。
A a;
A b = a; // b.p_str store the same address, that a.p_str
使用 unique_ptr
你不能 copy/assign 对象,但你可以移动它,而不用写移动 c-tor/move 赋值运算符。
A a;
A b = a; // cannot do this, since `unique_ptr` has no copy constructor.
A b = std::move(a); // all is okay, now `b` stores `unique_ptr` with data and `a` stores `nullptr`
但实际上,我不知道为什么你应该在这里存储指针,而不仅仅是 std::string
类型的对象,这是你的示例中的最佳解决方案。
除了 ForEveR 的回复,使用 unique_ptr
告诉 reader 只有一个对象 指代(在本例中,拥有)那个字符串。使用裸指针,无论谁正在阅读您的代码,都不知道有多少其他对象、局部变量或其他任何东西(单例?全局变量?)访问 and/or 修改该字符串。