【问题标题】:Prepend std::string前置 std::string
【发布时间】:2012-01-18 02:37:33
【问题描述】:

添加std::string 最有效的方法是什么?是否值得写出整个函数来这样做,还是只需要 1 - 2 行?我没有看到任何与 std::string::push_front 相关的内容。

【问题讨论】:

  • 有什么理由你不能做像s = a + s这样的事情吗?
  • 前置是什么意思?是@MikeBantegui 提到的吗?或者您正在尝试做其他事情?
  • 附加到字符串不会有效率,也许在完成后附加到字符串并反转它可能会更好?
  • @GWW:这样真的更有效率吗?
  • 你的意思是在 to 前面加上std::string 吗?然后加什么?

标签: c++ string prepend


【解决方案1】:

如果你使用std::string::append,你应该意识到以下是等价的:

std::string lhs1 = "hello ";
std::string lhs2 = "hello ";
std::string rhs = "world!";

lhs1.append(rhs);
lhs2 += rhs; // equivalent to above
// Also the same:
// lhs2 = lhs2 + rhs;

同样,“前置”等同于以下内容:

std::string result = "world";
result = "hello " + result;
// If prepend existed, this would be equivalent to
// result.prepend("hello");

你应该注意到,虽然这样做是相当低效的。

【讨论】:

  • 有谁知道为什么这个答案被否决了?它的说法是否不正确?我们,5 年后的读者,打算从无法解释的反对票中推断出什么?这对任何人都没有帮助。终于有人能详细说明了吗?
  • @underscore_d 正如另一个答案中提到的,使用 operator+ 将必须创建字符串的副本。相反,使用insert() 可以就地操作(好吧,在可能重新分配字符串缓冲区之后)。这对于这些小示例无关紧要,但对于大字符串可能很重要。在 C++11 中,也可以说 "result = "hello" + std::move(result)` 以避免复制。
  • @amon 谢谢!现在这似乎很明显,经过 2 年的进一步学习并且您指出了这一点,但实际上仍然值得一提。 move() 技巧是我有时为了方便而使用的技巧,但 C++ 是否真的保证任何地方都可以通过使用 .insert() 进行优化,或者如果他们聪明的话,这只是库实现者可以做的事情吗?我假设是后者。
【解决方案2】:
myString.insert(0, otherString);

让标准模板库的编写者担心效率;充分利用他们的所有工作时间,而不是重新编程轮子。

这两种方式都可以。

只要您使用的 STL 实现经过深思熟虑,您就会拥有高效的代码。如果您使用的是写得不好的 STL,那么无论如何您都会遇到更大的问题 :)

【讨论】:

  • 智能实现无法挽救低效算法。
【解决方案3】:

其实和不存在的std::string::push_front有类似的功能,看下面的例子。


Documentation of std::string::insert

#include <iostream>
#include <string>

int
main (int argc, char *argv[])
{
  std::string s1 (" world");
  std::string s2 ("ello");

  s1.insert (0,     s2); // insert the contents of s2 at offset 0 in s1
  s1.insert (0, 1, 'h'); // insert one (1) 'h'        at offset 0 in s1

  std::cout << s1 << std::endl;
}

输出:

hello world

由于在字符串前添加数据可能需要重新分配和复制/移动现有数据,您可以通过使用 std::string::reserve(预先分配更多内存)摆脱重新分配部分来获得一些性能优势。

遗憾的是,数据的复制/移动是不可避免的,除非您定义自己的自定义类,该类的行为类似于 std::string,它分配一个大缓冲区并将第一个内容放置在此内存缓冲区的中心。

如果缓冲区足够大,那么您可以在不重新分配和移动数据的情况下预先添加和附加数据。显然,从 source 复制到 destination 仍然是必需的。


如果你有一个缓冲区,你知道你会比你更频繁地添加数据追加一个很好的选择是将字符串向后存储,并在需要时将其反转(如果这种情况更罕见的话)。

【讨论】:

  • 我还想补充一点,如果您需要在一个字符串前面添加多个项目,您可以通过首先附加项目然后使用 std::rotate from .
【解决方案4】:

有一个重载的string operator+ (char lhs, const string&amp; rhs);,所以你可以用your_string 'a' + your_string来模仿push_front

这不是就地的,而是创建一个新的字符串,所以不要指望它是有效的。对于(可能)更有效的解决方案,使用resize 收集空间,std::copy_backward 将整个字符串向后移动一个并在开头插入新字符。

【讨论】:

  • 你应该使用std::string::resize来“收集更多空间”,如果需要,该函数会使内部缓冲区更大,这是真的。但它也会用char()'s(也称为NULL(即值0)填充当前字符串。请参阅此codepad paste进行演示。
猜你喜欢
  • 2014-06-21
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多