我希望在我的自定义C++字符串类中实现写时复制(copy-on-write),不知道该怎么做。
我尝试了一些选项,但它们都非常低效。
我希望在我的自定义C++字符串类中实现写时复制(copy-on-write),不知道该怎么做。
我尝试了一些选项,但它们都非常低效。
class MyString {
...
private:
class Buf {
...
private:
::std::size_t refct_;
char *data_;
};
::std::size_t len_;
::std::size_t alloclen_;
Buf *data_;
};
现在,你可以进行进一步的优化。那里的Buf类看起来似乎并没有包含或执行太多操作,这是真的。此外,它需要分配一个Buf实例和一个缓冲区来保存字符。这似乎相当浪费。因此,我们将采用常见的C实现技术,使用可伸缩缓冲区:
class MyString {
...
private:
struct Buf {
::std::size_t refct_;
char data_[1];
};
void resizeBufTo(::std::size_t newsize);
void dereferenceBuf();
::std::size_t len_;
::std::size_t alloclen_;
Buf *data_;
};
void MyString::resizeBufTo(::std::size_t newsize)
{
assert((data_ == 0) || (data_->refct_ == 1));
if (newsize != 0) {
// Yes, I'm using C's allocation functions on purpose.
// C++'s new is a poor match for stretchy buffers.
Buf *newbuf = ::std::realloc(data_, sizeof(*newbuf) + (newsize - 1));
if (newbuf == 0) {
throw ::std::bad_alloc();
} else {
data_ = newbuf_;
}
} else { // newsize is 0
if (data_ != 0) {
::std::free(data_);
data_ = 0;
}
}
alloclen_ = newsize;
}
data_->data_
视为包含alloclen_
字节而不仅仅是1个字节的内容。refct_
是一种类型,您拥有原子增量、原子减量和测试指令。CoW并不复杂。基本上,当你想要更改它时,你就进行复制,并让任何不想更改它的人保留对旧实例的引用。你需要使用引用计数来跟踪仍在引用对象的人,并且由于你正在创建一个新副本,所以需要减少“旧”实例的计数。一种快捷方式是在该计数为1(即只有你自己的引用)时不进行复制。
除此之外,除非你面临特定的问题,否则没有什么可以说的了。
你可能想要模仿其他语言(如Python、C#)中具有的“不可变”字符串。
这个想法是每个字符串都是不可变的,因此对字符串的任何操作都会创建一个新的不可变字符串...或者这是基本的想法,为了避免爆炸,如果存在相似的字符串,则不需要创建另一个。
template <class T> struct cow {
typedef boost::shared_ptr<T> ptr_t;
ptr_t _data;
ptr_t get()
{
return boost::atomic_load(&_data);
}
void set(ptr_t const& data)
{
boost::atomic_store(&_data, data);
}
}