其他分享
首页 > 其他分享> > c – std :: string实现和表达式模板

c – std :: string实现和表达式模板

作者:互联网

似乎std :: string – 因为它不使用表达式模板 – 对于某些操作(如串联)具有O(n ^ 2)复杂度而不是可能的O(n)复杂度.当你必须插入许多元素时,std :: stringstream类也是如此.

我想理解这一点,至少如果有人能够就这一点找到一些很好的联系.

解决方法:

将多个字符串连接在一起在C中具有不同的复杂性,具体取决于它是如何完成的.我相信你想到的情况是:

string result = string("Hello, ") + username + "! " +
                "Welcome to " + software_product + ".";

它连接6个字符串.第一个字符串被复制5次,第二个被复制4次,依此类推.正如Leonid Volnitsky在他的回答中所指出的,这个Θ(NM)的确切界限,其中M是连接操作的数量,N是被连接的字符串的总长度.当M <= N时,我们也可以将其称为O(N ^ 2).注意,它不能保证M <= N,因为你可以通过尝试连接空字符串来增加M而不增加N. 表达式模板可以帮助加速这个用例,尽管它会导致C 11中的auto和decltype类型推断以及C 98中的模板类型推断出现问题.所有这些都会推断出类型

auto result = string("Hello, ") + username + "! " +
              "Welcome to " + software_product + ".";

是一个懒惰评估的字符串模板类型,用于使表达式模板魔术发生.表达模板不是一个好主意的其他原因包括Leonid Volnitsky关于这个减慢编译时间的答案.它可能还会增加已编译二进制文件的大小.

相反,C中还有其他解决方案可用于获得Θ(N)级联:

string result = "Hello, ";
result += username;
result += "! ";
result += "Welcome to ";
result += software_product;
result += ".";

在此版本中,字符串已就地修改,虽然有时需要重新复制已复制到结果中的数据,但C字符串通常实现为dynamic arrays,它以指数方式分配新空间,以便每个新字符的插入需要分摊恒定时间,导致重复级联的整体Θ(N)行为.

以下是一种做同样事情的方法,几乎​​在一条线上.它在内部使用相同的原理,但也支持使用<<<<<<超载.

stringstream result;
result << "Hello, " << username << "! " << "Welcome to " << software_product
       << ".";
// do something with result.str()

最后,C标准库不包含此内容,但可以在其中定义以下函数,其中包含一些stringstream magic.实施留给读者练习.

template <typename... Items>
std::string concat(std::string const& a, std::string const& b, Items&&... args)

然后,您可以在O(N)时间内在一行上调用concat重复连接:

string result = concat("Hello, ", username, "! ", "Welcome to ",
                       software_product, ".");

据推测,所有这些都是比通过创建表达式模板类型搞乱类型推断更好的解决方案.

标签:c,string,complexity-theory
来源: https://codeday.me/bug/20190729/1569808.html