我正在嘗試在不使用 unique_ptr 的情況下撰寫 pImpl。我在寫這樣的東西時不明白:
class PublicClass
{
public:
// Some stuff
PublicClass();
private:
class ImplClass;
ImplClass&& mImpl;
};
class PublicClass::ImplClass
{
public:
ImplClass() {}
};
PublicClass::PublicClass() : mImpl(ImplClass()){}
產生以下編譯錯誤
Reference member 'mImpl' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object
在撰寫以下內容時
PublicClass::PublicClass() : mImpl(std::move(ImplClass())){}
沒關系。R 值參考不應該像第一個片段那樣延長臨時物件的生命周期?
uj5u.com熱心網友回復:
從class.temporary:
第二個背景關系是參考系結到臨時的。參考系結到的臨時物件或作為參考系結到的子物件的完整物件的臨時物件在參考的生命周期內持續存在,除了:
- 臨時系結到建構式的 ctor-initializer ([class.base.init]) 中的參考成員將持續存在,直到建構式退出。
這適用于您的兩個示例。也就是說,在您給定的兩種情況下,您都有一個懸空的參考。只是在您的示例的情況 2 中,編譯器無法向我們提供適當的錯誤/警告。
uj5u.com熱心網友回復:
首先,您必須了解每個物件都需要存盤。您有 3 個存盤空間:
- 堆
- 堆
- 靜態存盤(定義全域變數的地方)
兩者PublicClass和PublicClass::ImplClass都是類,要創建此類的實體,您需要存盤。
因此,您首先決定要在哪里分配ImplClass.
如果您希望能夠同時在堆疊上分配PublicClass,PublicClass::ImplClass編譯器必須知道ImplClass在編譯時的大小。我的意思是,如果在創建物件時在編譯時不知道物件的大小,則您無法在堆疊上分配物件。char[N]您可以做的是使用變數預分配記憶體
class PublicClass
{
// must be large enough to fit the ImplClass
static constexpr auto PublicClassImplSize = 128;
// The storage for ClassImpl
char alignas(void*) impl_[PublicClassImplSize];
class ImplClass;
public:
PublicClass();
~PublicClass();
};
// cpp
#include <new>
class PublicClass::ImplClass
{
char buf1[10];
// char buf2[10000];
};
PublicClass::PublicClass()
{
static_assert(sizeof(ImplClass) <= PublicClassImplSize);
new (impl_) ImplClass();
}
PublicClass::~PublicClass()
{
reinterpret_cast<ImplClass*>(impl_)->~ImplClass();
}
int main()
{
PublicClass o;
}
如果您不關心ImplClass分配的位置,則可以在堆上分配它。在這種情況下,您使用new/delete運算子來分配/釋放記憶體并在內部實作 RAIIPublicClass來管理資源。
unique_ptr is an example of the RAII-class. If for any reason you do not want to use it, you must implement the RAII inside the PublicClass. I.e. you implement constructor which allocates the ClassImpl on the heap and you implement the destructor, which releases the resources. You also have to care about move/copy constructors and move/assignment operators, as default behaviour provided by C language does not work right here.
class PublicClass
{
class ImplClass;
ImplClass* impl_{nullptr};
public:
PublicClass();
~PublicClass();
PublicClass(PublicClass&&) noexcept;
PublicClass& operator=(PublicClass&&) noexcept;
};
// cpp
#include <new>
#include <memory>
class PublicClass::ImplClass
{
char buf1[10];
// char buf2[10000];
};
PublicClass::PublicClass()
{
auto impl = std::make_unique<ImplClass>();
// ... more initialization
// Initialization is completed
impl_ = impl.release();
}
PublicClass::PublicClass(PublicClass&& obj) noexcept
: impl_(std::exchange(obj.impl_, nullptr))
{
}
PublicClass& PublicClass::operator=(PublicClass&& obj) noexcept
{
delete impl_;
impl_ = std::exchange(obj.impl_, nullptr);
return *this;
}
PublicClass::~PublicClass()
{
delete impl_;
}
int main()
{
PublicClass o;
}
In case if by design you have only one instance of the object, you can allocate the ClassImpl in the global namespace. Personally, I do not like this solution.
Update
I mean you cannot allocate the object on the stack if the size of the object is not known at compile time at the point where object is created
The use of alloca function is out of scope :)
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/444267.html
上一篇:在遞回插入排序中出現分段錯誤
下一篇:CPP列舉作為模板標志
