簡體   English   中英

如何在不復制和保留std :: string對象的情況下獲取C ++ std :: string char數據的所有權?

[英]How can I take ownership of a C++ std::string char data without copying and keeping std::string object?

如何在不復制和保留源std :: string對象的情況下獲取std :: string char數據的所有權? (我想使用移動語義但在不同類型之間。)

我使用C ++ 11 Clang編譯器和Boost

基本上我想做一些與此相當的事情:

{
    std::string s(“Possibly very long user string”);
    const char* mine = s.c_str();

    // 'mine' will be passed along,
    pass(mine);

    //Made-up call
    s.release_data();

    // 's' should not release data, but it should properly destroy itself otherwise.
}

為了澄清,我確實需要擺脫std :: string:繼續前進。 該代碼處理字符串和二進制數據,並應以相同的格式處理它。 我確實想要來自std :: string的數據,因為它來自另一個與std :: string一起使用的代碼層。

為了給出更多透視圖,我想要這樣做:例如,我有一個異步套接字包裝器,它應該能夠從用戶那里獲取std :: string和二進制數據進行寫入。 兩個“API”寫入版本(將std :: string或行二進制數據)內部解析為相同(二進制)寫入。 我需要避免任何復制,因為字符串可能很長。

WriteId     write( std::unique_ptr< std::string > strToWrite )
{

    // Convert std::string data to contiguous byte storage
    // that will be further passed along to other
    // functions (also with the moving semantics).
    // strToWrite.c_str() would be a solution to my problem
    // if I could tell strToWrite to simply give up its
    // ownership. Is there a way?

    unique_ptr<std::vector<char> > dataToWrite= ??

    //
    scheduleWrite( dataToWrite );
}

void scheduledWrite( std::unique_ptr< std::vecor<char> > data)
{
    …
}

這個例子中的std :: unique_ptr用於說明所有權轉移:任何其他具有相同語義的方法對我來說都沒問題。

我想知道這個特定情況的解決方案(使用std :: string char緩沖區)和字符串,流和類似的一般問題:在字符串,流,std容器和緩沖區類型之間接近移動緩沖區的提示。

我還要感謝有關C ++設計方法和特定技術的提示和鏈接,以便在不復制的情況下在不同的API /類型之間傳遞緩沖區數據。 我提到但不使用流,因為我對這個主題感到不穩定。

如何在不復制和保留源std :: string對象的情況下獲取std :: string char數據的所有權? (我想使用移動語義但在不同類型之間)

你不能安全地做到這一點。

對於特定的實現,在某些情況下,你可以做一些非常糟糕的事情,比如使用別名來修改字符串中的私有成員變量,以欺騙字符串使其認為它不再擁有緩沖區。 但即使你願意嘗試這一點,也不會一直有效。 例如,考慮小字符串優化,其中字符串沒有指向保存數據的某個外部緩沖區的指針,數據在字符串對象本身內。


如果要避免復制,可以考慮將接口更改為scheduledWrite。 一種可能性是:

template<typename Container>
void scheduledWrite(Container data)
{
    // requires data[i], data.size(), and &data[n] == &data[0] + n for n [0,size)
    …
}

// move resources from object owned by a unique_ptr
WriteId write( std::unique_ptr< std::vector<char> > vecToWrite)
{
    scheduleWrite(std::move(*vecToWrite));
}

WriteId write( std::unique_ptr< std::string > strToWrite)
{
    scheduleWrite(std::move(*strToWrite));
}

// move resources from object passed by value (callers also have to take care to avoid copies)
WriteId write(std::string strToWrite)
{
    scheduleWrite(std::move(strToWrite));
}

// assume ownership of raw pointer
// requires data to have been allocated with new char[]
WriteId write(char const *data,size_t size) // you could also accept an allocator or deallocation function and make ptr_adapter deal with it
{
    struct ptr_adapter {
        std::unique_ptr<char const []> ptr;
        size_t m_size;
        char const &operator[] (size_t i) { return ptr[i]; }
        size_t size() { return m_size; }
    };

    scheduleWrite(ptr_adapter{data,size});
}

此類使用move語義和shared_ptr獲取字符串的所有權:

struct charbuffer
{
  charbuffer()
  {}

  charbuffer(size_t n, char c)
  : _data(std::make_shared<std::string>(n, c))
  {}

  explicit charbuffer(std::string&& str)
  : _data(std::make_shared<std::string>(str))
  {}

  charbuffer(const charbuffer& other)
  : _data(other._data)
  {}

  charbuffer(charbuffer&& other)
  {
    swap(other);
  }

  charbuffer& operator=(charbuffer other)
  {
    swap(other);
    return *this;
  }

  void swap(charbuffer& other)
  {
    using std::swap;
    swap(_data, other._data);
  }

  char& operator[](int i)
  { 
    return (*_data)[i];
  } 

  char operator[](int i) const
  { 
    return (*_data)[i];
  } 

  size_t size() const
  {
    return _data->size();
  }

  bool valid() const
  { 
    return _data;
  }

private:
  std::shared_ptr<std::string> _data;

};

用法示例:

std::string s("possibly very long user string");

charbuffer cb(std::move(s)); // s is empty now

// use charbuffer...

您可以使用多態來解決此問題。 基類型是統一數據緩沖區實現的接口。 那么你將有兩個派生類。 一個用於std::string作為源,另一個用於您自己的數據表示。

struct MyData {
    virtual void * data () = 0;
    virtual const void * data () const = 0;
    virtual unsigned len () const = 0;
    virtual ~MyData () {}
};

struct MyStringData : public MyData {
    std::string data_src_;
    //...
};

struct MyBufferData : public MyData {
    MyBuffer data_src_;
    //...
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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