std::shared_ptr<std::string const> 可以作为引用计数的不可变字符串的有效实现吗?
Can std::shared_ptr<std::string const> serve as an efficient implementation of reference-counted immutable strings?
理想情况下,不可变的字符串类只需要为每个字符串分配一个内存。甚至引用计数也可以存储在保存字符串本身的同一内存块中。
string
和shared_ptr
的简单实现将为shared_ptr<string const>
分配三个不同的内存片段:
- 字符串缓冲区的内存
- 字符串对象的内存
- 参考计数的内存
现在,我知道当使用std::make_shared()
时,智能实现可以将最后两个合并到一个分配中。但这仍然会留下两个分配。
当您知道字符串是不可变的时,字符串缓冲区不会被重新分配,因此应该可以将其与字符串对象集成,只留下一个分配。
我知道一些字符串实现已经对短字符串使用了这样的优化,但我追求的是一个无论字符串长度如何都这样做的实现。
我的问题是:我的推理合理吗?实现是否真的允许并且能够做到这一点?我可以合理地期望一个高质量的标准库来实现这种优化吗?您知道这样做的当代库实现吗?
还是这是我必须自己实施的东西?
我相信唯一的方法是接受运行时变量大小数组的make_shared
。标准版本没有,即使从 c++17 开始(它增加了对数组shared_ptr
的支持)。
另一方面,Boost具有boost::make_shared
,它也可以采用数组大小参数。一旦你拥有了它,你就是金色的;你会得到一个几乎可以做你想要的shared_ptr<char[]>
(除了实际上是一个std::string
。
如果你不想使用boost,你可以自己动手。这可能不会那么难。
另外需要考虑的是,如果您只创建 O(1) 字符串,那么永远不删除它们并传递原始指针(或std::string_view
s)会快得多。这样可以避免任何复制或摆弄引用计数。(引用计数实际上非常慢,因为它们使用原子操作。
您也可以使用像std::unordered_set<std::string>
这样的实习机制。
您可能需要为所有分配使用自定义分配器。
class ImmutableStringAllocator;
template<typename CharT>
using immutable_string = std::basic_string<CharT, std::char_traits<CharT>, ImmutableStringAllocator>
template<size_t N>
immutable_string<char> make_immutable_string(char (&data)[N])
{
ImmutableStringAllocator alloc(N);
// going for basic_string::basic_string(charT *, size_t, Allocator)
return allocate_shared<immutable_string<char>>(alloc, data, N, alloc);
}
class ImmutableStringAllocator {
size_t len;
size_t offset;
char * buf;
std::reference_wrapper<char *> ref;
public:
// Normal Allocator stuff here
ImmutableStringAllocator(size_t N) : len(N), buf(nullptr), offset(0), ref(buf) {}
ImmutableStringAllocator(const ImmutableStringAllocator & other) : len(other.len), buf(nullptr), offset(other.offset), ref(other.buf) {}
ImmutableStringAllocator operator=(const ImmutableStringAllocator & other)
{
assert(buf == nullptr);
temp(other);
swap(*this, temp);
return *this;
}
pointer allocate(size_type n, const_void_pointer hint)
{
if (!ref.get()) { buf = ::new(n + len); offset = n; return buf; }
return ref.get() + offset;
}
}
- 正在寻找C++不可变的hashset/hashmap
- 具有常量属性的不可变类
- 命名空间 std:: 不包含可选
- std 不包含,但它应该添加库
- 为什么将函数传递给内核会导致数据变得不可变?
- 现代c++编译器会优化不可变的临时变量吗
- C++中的不可变列表
- 如何将地图作为不可变地图传递?
- 不可变的全局对象应该声明为"const my_result_t BLAH"还是"extern const my_result_t BLAH;"?
- 向不可变纹理存储提供数据
- 在C++中创建不可变且高效的类的惯用方法
- std::shared_ptr<std::string const> 可以作为引用计数的不可变字符串的有效实现吗?
- 编写接受可变跨度作为不可变跨度的模板函数
- 可变存储与不可变存储
- 不可变数据模型的内存管理
- 在C++中创建不可变对象的更好方法
- 返回值std ::不匹配的相等向量
- 如何使用分支逻辑构造不可变数据类型的实例
- 不可变的 lambda 函数:复制捕获的变量是否允许是 const
- C++ 不可变的自定义类按引用或值传递