C++ 我如何获得C++;std::string char数据,而不复制和保留std::string对象?

C++ 我如何获得C++;std::string char数据,而不复制和保留std::string对象?,c++,string,c++11,buffer,iostream,C++,String,C++11,Buffer,Iostream,在不复制和不保留源std::string对象的情况下,如何获得std::string char数据的所有权?(我想在不同类型之间使用移动语义。) 我使用C++11编译器和 基本上,我想做一些与此等效的事情: { std::string s(“Possibly very long user string”); const char* mine = s.c_str(); // 'mine' will be passed along, pass(mine);

在不复制和不保留源std::string对象的情况下,如何获得std::string char数据的所有权?(我想在不同类型之间使用移动语义。)

我使用C++11编译器和

基本上,我想做一些与此等效的事情:

{
    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::字符串或行二进制数据)在内部解析为相同的(二进制)写入。我需要避免任何复制,因为字符串可能很长

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)
{
    …
}
WriteId写入(std::unique_ptrstrotwrite)
{
//将std::字符串数据转换为连续字节存储
//这将进一步传递给其他人
//函数(也具有移动语义)。
//strToWrite.c_str()可以解决我的问题
//如果我能告诉StrotWrite放弃它的
//所有权,有办法吗?
唯一_ptr dataToWrite=??
//
scheduleWrite(dataToWrite);
}
void scheduledWrite(std::unique_ptr数据)
{
…
}
在本例中,std::unique_ptr用于说明所有权转移:任何其他具有相同语义的方法对我来说都很好

我想知道这个特定情况(使用std::string char buffer)的解决方案,以及字符串、流和类似的一般问题:在字符串、流、std容器和缓冲区类型之间移动缓冲区的技巧

我也会感谢C++的设计方法和技巧,以及在没有复制的情况下,在不同API类型之间传递缓冲区数据的技巧和链接。我提到但没有使用流,因为我在这个问题上不确定

在不复制和不保留源std::string对象的情况下,如何获得std::string char数据的所有权?(我想在不同类型之间使用移动语义)

你不能安全地这样做

对于特定的实现,在某些情况下,您可以做一些可怕的事情,比如使用别名来修改字符串中的私有成员变量,从而诱使字符串认为它不再拥有缓冲区。但即使你愿意尝试,它也不总是有效的。例如,考虑一个小字符串优化,其中一个字符串没有指向某个外部缓冲区来保存数据的指针,数据在字符串对象本身内部。

如果您想避免复制,可以考虑将接口更改为计划写入。一种可能性是:

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});
}
模板
作废scheduledWrite(容器数据)
{
//需要数据[i]、数据.size()和&data[n]==&data[0]+n表示n[0,size)
…
}
//从唯一\u ptr拥有的对象中移动资源
WriteId写入(std::unique_ptrvecToWrite)
{
scheduleWrite(std::move(*vecToWrite));
}
WriteId写入(std::unique_ptrstrotWrite)
{
scheduleWrite(std::move(*strToWrite));
}
//从按值传递的对象移动资源(调用者还必须注意避免复制)
WriteId写入(std::string strotwrite)
{
scheduleWrite(std::move(strToWrite));
}
//假定原始指针的所有权
//要求已使用新字符[]分配数据
WriteId write(char const*data,size\u t size)//您还可以接受一个分配器或释放函数,并让ptr\u适配器处理它
{
结构ptr_适配器{
std::唯一的ptr ptr;
大小;
字符常量和运算符[](size_t i){return ptr[i];}
size\u t size(){返回m\u size;}
};
scheduleWrite(ptr_适配器{数据,大小});
}

您可以使用多态性来解决此问题。基类型是统一数据缓冲区实现的接口。然后您将有两个派生类。一个用于
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_;
    //...
};

此类使用移动语义和共享\u 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::unique\u ptr
将是唯一允许类似操作的方法。@minsk:我想每个人都清楚你的场景,但你不会明白它--这是不可能的。.-]另外,您知道
std::string
存储二进制数据(包括嵌入的空值)很好,对吗?你确定你不能继续使用
std::string
?@minsk:Er,使用
size()
length()
——它们都不关心嵌入的空值(如果你想要可靠的信息,使用而不是cpluplus.com:-])。@minsk:想要这样做很合理,不幸的是不可能的,因为类的设计不允许它。@明斯克:你不知道缓冲区应该如何释放。由于没有
release
成员,您无法使用
string
实现您想要的功能。这些都是优点:小字符串优化和知道如何释放另一个实现缓冲区。关于std::stringstream,我可以将std::string移动到std::stringstream中吗?它公开了它的缓冲区?这些都是std对象,std::stringstream知道std::string。。我真的很想找到一个解决方案,避免复制并允许部分代码处理字符串:(@Alexandre:我不想一直保留std::string,因为我想在内部统一字符串或二进制的实现
std::string s("possibly very long user string");

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

// use charbuffer...