智能指针(unique_ptr)代替原始指针作为类成员



给定一个类层次:

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;
}

有一个指向string的p_str指针(不管它指向什么对象)。

除了不写delete p_str外,将其替换为std::unique_ptr有什么好处吗?

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 B1n";
  }
  cout << "nB2::A2 (unique pointers)n";
  try {
    B2 b2;
  }
  catch (...) {
    cout << "Exception thrown for b2n";
  }
  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被自动删除。

使用原始指针,您可以进行双删除,因为您不需要手动实现复制c-tor和赋值操作符。

A a;
A b = a; // b.p_str store the same address, that a.p_str

使用unique_ptr,你不能复制/分配对象,但你可以移动它,而不需要写move 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告诉读者只有一个对象引用(在这种情况下,拥有)该字符串。使用裸指针,任何阅读代码的人都不知道有多少其他对象、局部对象或其他任何东西(单例对象?

相关内容

  • 没有找到相关文章

最新更新