[英]How to implement proper stack unwinding and raii when thrown a bad_alloc during construction
所以我正在設計一個將要處理大量內存的類,我想確保它在構造函數的內存分配期間出現問題時能正確展開。
這是我得到的:
class foo{
public:
foo(): var1(nullptr), var2(nullptr){
try{
var1 = new int(1);
var2 = new int(2);
}
catch(std::exception &e){
delete var1;
delete var2;
return;
}
//Some other things involving these variables
}
如果我只想在構造函數中的某些后續代碼因bad_alloc異常導致錯誤之前想要停止構造此對象,那么我是否正確地在catch塊中進行此返回? 或者catch塊在終止時是否取消構造函數? 我整個事情過於復雜嗎?
我想確保它在構造函數的內存分配期間出現問題時能正確展開。
然后你必須使你的代碼符合“一個類控制一個資源或做一個工作”的想法
#include <memory>
// foo has one job - to manage fooness.
// It no longer manages memory resources
class foo
{
public:
foo()
: var1(new int(1))
, var2(new int(2))
{
}
std::unique_ptr<int> var1; // unique_ptr only manages a resource
std::unique_ptr<int> var2; // unique_ptr only manages a resource
};
其他正確的初始化形式:
#include <memory>
// foo has one job - to manage fooness.
// It no longer manages memory resources
class foo
{
public:
foo()
: var1(std::make_unique<int>(1))
, var2(std::make_unique<int>(2))
{
}
std::unique_ptr<int> var1; // unique_ptr only manages a resource
std::unique_ptr<int> var2; // unique_ptr only manages a resource
};
默認值:
#include <memory>
// foo has one job - to manage fooness.
// It no longer manages memory resources
class foo
{
public:
// default constructor now implicit
std::unique_ptr<int> var1 = std::make_unique<int>(1); // unique_ptr only manages a resource
std::unique_ptr<int> var2 = std::make_unique<int>(2); // unique_ptr only manages a resource
};
正確,但慣用不愉快 - 冗余初始化:
#include <memory>
// foo has one job - to manage fooness.
// It no longer manages memory resources
class foo
{
public:
foo()
: var1(nullptr)
, var2(nullptr)
{
var1 = std::make_unique<int>(1);
var2 = std::make_unique<int>(2);
}
std::unique_ptr<int> var1; // unique_ptr only manages a resource
std::unique_ptr<int> var2; // unique_ptr only manages a resource
};
這是沒有構圖的一種方法。 注意沒有收益的所有額外復雜性:
#include <memory>
// foo now has two jobs - to manage fooness, and to manage resources.
// This adds un-necessary complication, bugs and maintenance overhead
class foo
{
public:
foo()
: var1(nullptr)
, var2(nullptr)
{
var1 = new int(1);
var2 = new int(2);
}
foo(const foo& other)
: var1(nullptr)
, var2(nullptr)
{
if (other.var1) {
var1 = new int(*(other.var1));
}
if (other.var2) {
var2 = new int(*(other.var2));
}
}
foo(foo&& other) noexcept
: var1(other.var1)
, var2(other.var2)
{
other.var1 = nullptr;
other.var2 = nullptr;
}
foo& operator=(const foo& other)
{
foo tmp(other);
std::swap(var1, tmp.var1);
std::swap(var2, tmp.var2);
return *this;
}
foo& operator=(foo&& other) noexcept
{
foo tmp(std::move(other));
std::swap(var1, tmp.var1);
std::swap(var2, tmp.var2);
return *this;
}
~foo() noexcept
{
delete var1;
delete var2;
}
int* var1; // doesn't manage anything
int* var2; // doesn't manage anything
};
你應該查看智能指針: std::unique_ptr
(在這種情況下會很有用)和std::shared_ptr
/ std::weak_ptr
(不是你的例子的正確類型,但很高興知道)。
只要您沒有重新實現某種智能指針,使用它們而不是動態分配,它將為您節省一些麻煩(即使您的示例是正確的並且不會泄漏,只要析構函數是正確的)。
您應該拋出異常而不是返回:應通知調用者構造失敗(如果分配失敗意味着構造函數失敗)。 RAII意味着對象永遠不應處於無效狀態。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.