是否允许在std :: string的实现中进行此优化?

Eva*_*ran 7 c++ optimization standard-library proxy-object

我只是想着实施std::string::substr.它返回一个新std::string对象,这对我来说似乎有点浪费.为什么不返回一个引用原始字符串内容的对象,并且可以隐式赋值给std::string?一种对实际复制的懒惰评价.这样的类看起来像这样:

template <class Ch, class Tr, class A>
class string_ref {
public:
    // not important yet, but *looks* like basic_string's for the most part

private:
    const basic_string<Ch, Tr, A> &s_;
    const size_type pos_;
    const size_type len_;    
};
Run Code Online (Sandbox Code Playgroud)

这个类的公共接口将模仿真实的所有只读操作std::string,因此使用将是无缝的.std::string然后可以有一个新的构造函数,string_ref因此用户永远不会更聪明.在您尝试"存储"结果的那一刻,您最终会创建一个副本,因此引用没有真正的问题指向数据,然后在其背后进行修改.

想法是这样的代码:

std::string s1 = "hello world";
std::string s2 = "world";
if(s1.substr(6) == s2) {
    std::cout << "match!" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

std::string总共不会构造2个对象.对于执行大量字符串操作的代码来说,这似乎是一种有用的优化.当然,这不仅适用于std::string任何可以返回其内容子集的类型.

据我所知,没有实现这样做.

我想问题的核心是:

给定一个可以根据需要隐式转换为类的类std::string,是否符合库编写者的标准,将成员的原型更改为返回类型?或者更一般地说,库编写者是否有余地在这些类型的情况下作为优化返回"代理对象"而不是常规对象?

我的直觉是,这是不允许的,原型必须完全匹配.鉴于您不能单独重载返回类型,这将使​​图书馆编写者无法利用这些类型的情况.就像我说的,我认为答案是否定的,但我想我会问:-).

GMa*_*ckG 6

这个想法是写时复制,但不是COW整个缓冲区,而是跟踪缓冲区的哪个子集是"真正的"字符串.(COW,正常形式,在某些库实现中使用(是?).)

所以你根本不需要代理对象或更改界面,因为这些细节可以完全在内部完成.从概念上讲,您需要跟踪四件事:源缓冲区,缓冲区的引用计数以及此缓冲区中字符串的开始和结束.

无论何时操作根本修改缓冲区,它都会创建自己的副本(从开始和结束分隔符开始),将旧缓冲区的引用计数减1,并将新缓冲区的引用计数设置为1.其余的引用计数规则是相同的:复制并将计数增加1,破坏字符串并将计数减1,达到零并删除等.

substr 只创建一个新的字符串实例,除了明确指定了开始和结束分隔符.