Учитывая иерархию классов:Смарт указатель (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;
}
Существует 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
удаляется автоматически, когда происходит исключение в конструкторе тот же класс, в котором был объявлен член.
«Если конструктор любого производного класса создает исключение, утечка памяти будет происходить в любом варианте кода». Вы уверены? * Мне кажется, что там [утечка не будет] (http://coliru.stacked-crooked.com/a/0aabaeaa456c99ec). Поскольку это дочерний объект, бросающий исключение в конструкторе, деструктор базового объекта будет вызываться при вызове исключения. – jaggedSpire
@jaggedSpire извините за «из любого производного», но если исключение произошло в конструкторе класса, где определен член, произойдет утечка памяти: http://coliru.stacked-crooked.com/a/3bd94aa1c8fbb7df – vladon
Это правильно , хотя и не то, что вы изначально утверждали. Просто помните, что будьте осторожны с вашей формулировкой - когда дело доходит до исключений, * где * вы бросаете разницу иногда. Поскольку вы исправили свое утверждение, чтобы он не сказал, что будет утечка памяти, если класс inheritor выдает исключение, я бы хотел удалить свой оригинальный комментарий. – jaggedSpire