[英]Trouble wrapping std::istream, unique_ptr not null after moved
由於std :: istream無法移動(受保護的函數),我試圖包裝std :: istream,以便我可以在自定義流工廠上構建我的代碼。
到目前為止,我嘗試直接從std :: istream繼承,如下所示:
class IStream : public std::istream{
public:
// template <typename T>
IStream(std::istringstream&& rhs) : std::istream(std::move(rhs)){
this->rdbuf(rhs.rdbuf());
rhs.istream::rdbuf(NULL);
}
IStream(IStream&& rhs) : std::istream(std::move(rhs)){
this->rdbuf(rhs.rdbuf());
rhs.rdbuf(NULL);
}
};
但它會導致分段錯誤(對原因的任何見解都會受到贊賞),所以我繼續采用一些“更安全”的方法。
這是我目前使用的代碼:
#include <iostream>
#include <sstream>
#include <istream>
#include <string>
#include <memory>
#include <cassert>
using namespace std;
class IStream {
public:
IStream(const IStream& rhs) = delete;
template <typename T>
IStream(T& rhs) : shared_(rhs) {
std::cout << "called IStream(T&)" << std::endl;
}
// assume strict order between member construct for now
template <typename T>
IStream(T&& rhs) : owned_{std::make_unique<T>(std::move(rhs))}, shared_(*owned_) {
std::cout << "called IStream(T&&)" << std::endl;
}
IStream(IStream&& rhs) : owned_(std::move(rhs.owned_)), shared_(*owned_) {
assert(rhs.owned_.get() == nullptr); // failed
std::cout << "called IStream(IStream&&)" << std::endl;
}
std::istream& get() {
return shared_;
}
~IStream() {
std::cout << "called ~IStream with " << (owned_.get()!=nullptr) << std::endl;
}
private:
std::unique_ptr<std::istream> owned_;
std::istream& shared_;
};
IStream&& wrap() {
return IStream(istringstream{"test"});
}
int main(void) {
IStream is(wrap());
char buf[10];
memset(buf, 0, sizeof(char) * 10);
is.get().getline(buf, 10);
std::cout << std::string(buf) << std::endl;
return 0;
}
可悲的是這段代碼仍然不起作用,我發現IStream::IStream(IStream&&)
斷言失敗了。
輸出:
called IStream(T&&)
called ~IStream with 1
Assertion failed: rhs.owned_.get() == nullptr, file .\tmp.cpp, line 23
這導致了移動后unique_ptr不為null的奇怪現象。
我正在使用MSVC編譯器btw。
你不能理所當然地做你想做的事。
據我所知,你想要一些盡可能與::std::istream
無法區分的對象,但是它具有移動語義,以便在不再需要它之后自動銷毀它。
可以被稱為::std::istream
的任何東西的主要有用屬性是它是從::std::istream
派生的,因為它是::std::istream
,它不能移動,沒有從中衍生出來也可以移動。
所以,你留下了下一個最好的東西, ::std::unique_ptr
到你的::std::istream
。 這意味着你將不得不一直使用*
,這將是丑陋的。 那好吧。
沒有多少聰明可以讓你創建任何類型的同時可移動的包裝器,並從::std::istream
派生,這樣它就可以使用所有期望的好的現有庫函數。 你也不能做出任何合理的行為,就像參考而沒有那個東西實際上是一個參考。
順便說一句,當你構造一個unique_ptr
你可以提供一個自定義刪除器,如果你實際上指向你不想刪除的::std::cin
類的東西。 在這種情況下,您可以使自定義刪除器完全不執行任何操作。 移動unique_ptr
時,自定義刪除器將與指針一起向右移動。
此函數返回懸空引用:
IStream&& wrap() {
return IStream(istringstream{"test"});
}
函數返回時會銷毀臨時對象。 而是將函數更改為按值返回, IStream wrap() {
。
此外, shared_(*owned_)
導致懸空引用,因為它引用當前擁有的對象所在的內存位置,即使該對象被銷毀並且unique_ptr稍后更改為擁有不同的對象。
擺脫shared_
是個好主意,只需根據需要調用owned_.get()
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.