std::string的一个隐蔽错误

std::string的一个隐蔽错误

先看第一个程序,for循环生成5个Key,然后把它们对应的字符串地址放入vector中,最后依次输出字符串。

#include <iostream>
#include <string>
#include <vector>

std::string GenKey(int i) {
  char buf[32];
  snprintf(buf, sizeof(buf), "key%06d", i);
  return std::string(buf);
}

int main() {
  std::vector<const char*> vec;

  for (int i=0; i < 5; i++) {
    std::string key = GenKey(i);
    vec.push_back(key.data());
  }
  
  for (auto p : vec) {
    std::cout << p << std::endl;
  }

  return 0;
}

从代码逻辑来说,应该会依次输出5个不同的Key才对,其实不然。
运行这段代码,你会发现输出是:

key000004
key000004
key000004
key000004
key000004

竟然输出了5个一模一样的Key!

我们再来一下第二个程序,它与第一个程序的唯一区别是,新增加了一个vector存储string类型的Key。

#include <iostream>
#include <string>
#include <vector>

std::string GenKey(int i) {
  char buf[32];
  snprintf(buf, sizeof(buf), "key%06d", i);
  return std::string(buf);
}

int main() {
  std::vector<std::string> strs;
  std::vector<const char*> vec;

  for (int i=0; i < 5; i++) {
    std::string key = GenKey(i);
    strs.push_back(key);
    vec.push_back(key.data());
  }
  
  for (auto p : vec) {
    std::cout << p << std::endl;
  }

  return 0;
}

运行第二个程序,输出:

key000000
key000001
key000002
key000003
key000004

这次输出和预期的一样了。

那第一个程序出现了什么错误呢?
这里有一个容易被忽视的错误:我们在for循环中定义的std::string key局部变量, 每次循环完成后key都会被销毁,那key对应的字符串数组当然也被释放了!循环结束后vec中存储的全是野指针,但是因为这些Key分配的堆空间都在相同的位置,所以vec中他们指向了相同的地址,翻译为字符串,即是最后一次循环赋值的key000004!
在第二个程序中,虽然key仍然是局部变量,但因为将他们存到了vector中,所以循环结束后,分配的堆空间也不会被释放(这里需要注意的一点是std::string类型是写时复制的,即std::string类型间相互赋值,但只要没有发生修改操作,它们底层的字符串都指向了相同的地址)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值