1

tmp我想知道是否可以在下面的代码中重用字符串内存。它的内存是否在每次迭代中重新分配?有没有更好的方法来处理这种情况?

string s, line;
map<string, string> mymap;
while(getline(file, line) {
  if(a) s = "_a";
  else if(b) s = "_b";
  string tmp = line + s;
  mymap.insert(tmp, s);
}
4

3 回答 3

4

tmp每次在循环周围创建和销毁,并在line. 因此,您可以像这样获得便宜的可能改进并且几乎不会变得更糟:

if(a) s = "_a";
else if(b) s = "_b";
line += s;
mymap.insert(line, s);

我还会给出s类型:为每个循环分配一次仅包含文字副本的循环const char*并没有多大意义。string但它确实string通过调用转换为insert,所以无论哪种方式都没有太多。

只要您不破坏代码的简单性/可读性/可维护性/设计来实现它,可能的改进和几乎不会变得更糟并不是过早的优化。line和的范围越大s,玩弄它们的风险就越大(分别改变值和改变类型),因为您可能会以某种方式误导读者/维护者。这是短函数很好的原因之一。

在 C++11 中,您可以编写mymap.insert(std::move(line), s);另一个简单的可能改进。

综上所述:您可能会发现,无论您做了多少不必要的复制和分配,所花费的时间与getline. 在这种情况下,有两种非常相似的代码编写方式,其中一种“应该”更有效。所以你不妨使用它,但不要高估它,认为它一定会有所作为。

于 2012-09-27T09:18:19.113 回答
3

while 循环的每次迭代都会创建和销毁您的字符串tmp对象。因此,正如已经建议的那样,第一步是移出tmpwhile 循环。这样您就不必每次迭代都构造一个新的字符串对象。但是,您仍然有tmp = line + s每次迭代都会导致内存重新分配的分配。使用 = 运算符创建参数的副本,并将副本分配给 tmp 字符串对象。因此,第二步是添加删除字符串对象mymap.insert(line+s, s);的需要的建议。tmp

我认为人们可以通过不分配"_a"或在每次迭代"_b"中字符串来继续这种改进。s这可以在while循环之外完成一次,然后根据内容ab不同的字符串对象可以添加到您的地图中。像这样的东西(注意这是未经测试的):

string a = "_a";
string b = "_b";
string line;
map<string, string> mymap;
while(getline(file, line) {
  if(a) mymap.insert(line+a, a);
  else if(b) mymap.insert(line+b, b);
}

有人可能会争论这是否很好,我认为 juanchopanza 的答案就足够了,因为它保持了代码的可读性。但我认为上面的代码制作的副本更少。

于 2012-09-27T08:51:56.383 回答
1

是的,使用 C++ 11 标准中引入的 STD::MOVE 语义。

更新:示例

#include <iostream>
#include <utility>
#include <vector>
#include <string>
int main()
{
    std::string str = "Hello";
    std::vector<std::string> v;

    // uses the push_back(const T&) overload, which means 
    // we'll incur the cost of copying str
    v.push_back(str);
    std::cout << "After copy, str is \"" << str << "\"\n";

    // uses the rvalue reference push_back(T&&) overload, 
    // which means no strings will copied; instead, the contents
    // of str will be moved into the vector.  This is less
    // expensive, but also means str might now be empty.
    v.push_back(std::move(str));
    std::cout << "After move, str is \"" << str << "\"\n";

    std::cout << "The contents of the vector are \"" << v[0]
                                         << "\", \"" << v[1] << "\"\n";
}
于 2012-09-27T08:26:39.960 回答