为什么传递字符串时,这个initializer_list使用会出现问题?

9
我尝试了我的G++版本的C++0x初始化列表实现,但它只输出空行。
#include <initializer_list>
#include <iostream>
#include <string>

int main() {
  std::initializer_list<std::string> a({"hello", "stackoverflow"});
  for(auto it = a.begin(), ite = a.end(); it != ite; ++it)
    std::cout << *it << std::endl;
}

我不知道我做错了什么。请问有谁可以帮助我吗?
2个回答

3
在上面的示例中,您似乎正在创建两个初始化程序列表。临时的{"hello", "stackoverflow"}std :: initializer_list<std :: string> a
在gcc上,{}初始化列表实际上是临时数组,在完整语句之后其生命周期结束(除非直接绑定到std :: initializer_list,如下例中的注释行所示)。
第一个列表的内部数组的生命周期在a的构造函数返回后立即结束,因此a的数组现在指向无效的内存(gcc仅复制指针)。 您可以检查,在进入循环之前,std :: string解构函数将被调用。
当您进入循环时,您正在读取无效的内存。
根据最新的标准草案(n3242),§18.9 / 1,甚至不能像那样复制初始化程序列表(它们不提供带参数的构造函数)。
#include <initializer_list>
#include <iostream>

class A
{
public:
  A(int)
  { }

  ~A()
  {
    std::cout << "dtor" << std::endl;
  }
};

int main()
{
  std::initializer_list<A> a({A(2), A(3)});
  // vs std::initializer_list<A> a{A(2), A(3)};
  std::cout << "after a's construction" << std::endl;
}

使用gcc 4.5.0,我得到了以下结果:

dtor
dtor
after a's construction

1
std::initializer_list<std::string> a({"hello", "stackoverflow"});

如果我声明为:

std::initializer_list<std::string> a{"hello", "stackoverflow"}; //without ()

那么它正在工作:http://ideone.com/21mvL

但这很奇怪。看起来像是编译器的错误。


编辑:

这绝对是编译器的 bug,因为如果我写 (*it).c_str() 它会打印出字符串!

std::initializer_list<std::string> a({"hello", "stackoverflow"}); //with ()
for(auto it = a.begin(), ite = a.end(); it != ite; ++it)
   std::cout << (*it).c_str() << std::endl;

代码:http://ideone.com/hXr7V


@ Johannes:如果你去掉 c_str(),它就无法输出 "hello":http://ideone.com/NTRUh ... 我很困惑。这是怎么回事? - Nawaz
1
这是因为你正在引用本地变量(当函数返回时,该变量会超出作用域)。 当您使用c_str()时,您只是幸运的(或不幸的,取决于观点),因为内存仍然包含对char *字符串的引用,并且堆区域尚未被覆盖。 :) - Vitus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接