簡體   English   中英

麻煩包裝std :: istream,unique_ptr在移動后不為null

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM