如何在不复制和保留std::string对象的情况下获得C++std::string字符数据的所有权?
如何在不复制和不保留源std::string对象的情况下获得std::string字符数据的所有权?(我希望在不同类型之间使用移动语义。)
我使用C++11Clang编译器和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或row二进制数据)在内部解析为相同的(二进制)写入。我需要避免任何复制,因为字符串可能很长。
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 buffer)以及字符串、流和类似的一般问题的解决方案:在字符串、流、STD容器和缓冲区类型之间移动缓冲区的技巧。
当涉及到在不同的API/类型之间传递缓冲区数据而不进行复制时,我还会感谢C++设计方法和特定技术的提示和链接。我提到但没有使用STREAMS,因为我在这个问题上犹豫不决。
解决方案
如何在不复制和不保留源std::string对象的情况下获得std::string字符数据的所有权?(我希望在不同类型之间使用移动语义)
您不能安全地执行此操作。
对于特定的实现,在某些情况下,您可能会做一些可怕的事情,比如使用别名来修改字符串中的私有成员变量,以欺骗字符串认为它不再拥有缓冲区。但是,即使你愿意尝试,它也不会总是奏效。例如,考虑小字符串优化,其中字符串没有指向保存数据的某个外部缓冲区的指针,数据位于字符串对象本身内。
如果希望避免复制,可以考虑将接口更改为SchededWrite。一种可能性类似于:
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});
}
相关文章