【发布时间】:2011-01-13 16:41:47
【问题描述】:
我只是在考虑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_;
};
这个类的公共接口将模仿真实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;
}
总共构造的 std::string 对象不超过 2 个。对于执行大量字符串操作的代码,这似乎是一个有用的优化。当然,这不仅适用于std::string,还适用于任何可以返回其内容子集的类型。
据我所知,没有实现这样做。
我想问题的核心是:
给定一个可以根据需要隐式转换为std::string 的类,库编写者将成员的原型更改为返回类型是否符合标准?或者更一般地说,库编写者是否有余地在这些类型的情况下返回“代理对象”而不是常规对象作为优化?
我的直觉是这是不允许的,原型必须完全匹配。鉴于您不能仅对返回类型进行重载,那么库编写者将没有空间利用这些类型的情况。就像我说的,我认为答案是否定的,但我想我会问:-)。
【问题讨论】:
-
@Evan:您可能想阅读 The C++ Programming Language - 它提供了这个概念的实现。尽管如此,这样的 string_ref 很容易失效,并且复制通常相对便宜,因此通常人们很乐意复制到新字符串中。当我实现这样一个类时,我倾向于根据 const char* 和大小来做,这使得它更广泛地适用(例如,将它覆盖在内存映射文件、const char[] 数据等)。如果您需要独立于源来更改子字符串,那么事情很快就会变得复杂,尤其是在线程环境中......
-
@Tony: 喜欢
llvm::StringRef? -
当您执行 substr() 时,您不会认为 std::string 的 COW 实现尚未重用原始字符串的缓冲区。
-
@Matthieu:是的,很像 llvm::StringRef - 我敢肯定每个有经验的注重性能的 C++ 程序员都会抛出一个或三个版本...
-
@Martin York:我不知道任何适用于原始字符串子字符串的 COW 实现。这并不意味着他们不在那里,只是我似乎没有。
标签: c++ optimization standard-library proxy-object