使用std::getenv时,char*和string之间的意外差异。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用std::getenv时,char*和string之间的意外差异。相关的知识,希望对你有一定的参考价值。

我的代码看起来像这样。

#include <cstdlib>
#include <iostream>
#include <string>

std::string string_from_env(std::string var) {
  std::string out = std::getenv(var.c_str());
  return out;
}

int main() {
  const char* x1 = string_from_env("TEST_HOST").c_str();
  const char* x2 = string_from_env("TEST_USER").c_str();
  const char* x3 = string_from_env("TEST_NAME").c_str();

  std::cout << x1 << " " << x2 << " " << x3 << std::endl;

  const std::string y1 = string_from_env("TEST_HOST");
  const std::string y2 = string_from_env("TEST_USER");
  const std::string y3 = string_from_env("TEST_NAME");

  std::cout << y1 << " " << y2 << " " << y3 << std::endl;
}

如果我运行

export TEST_HOST=host
export TEST_USER=user
export TEST_NAME=name
g++ --std=c++2a test.cc  # version 9.3.0
./a.out

然后,输出是

name name name
host user name

为什么 char* 版本结果 x1,x2,x3 所有印刷 namestd::string 版本是否能正常工作?

有什么方法可以让我修改 string_from_env 函数,这样同样的代码就会打印出 host user name 而不是 name name name?

答案

返回的指针 std::string::c_str 指的是该公司所拥有的内存。string 对象。 当 string 被破坏(甚至以某种方式变异),该指针就会失效。

由于临时的 string 返回的对象 string_from_env 中的前三个调用并没有立即绑定到引用上,而是在包含函数调用的完整表达式结束时被销毁。 这意味着 x1, x2x3 都会在创建后立即失效。 试图从它们中读取数据将导致未定义的行为。

另一答案

考虑这一行

const char* x1 = string_from_env("TEST_HOST").c_str();

你不存储调用 string_from_env("TEST_HOST")所以它返回的临时字符串将在表达式结束时被销毁。所以 x1 将指向一个已经销毁的字符串的内部缓冲区。你的代码有未定义的行为。

原因是 x1, x2x3 都指向同一个字符串,这与小字符串优化有关,这是std::string的一个实现细节。

以上是关于使用std::getenv时,char*和string之间的意外差异。的主要内容,如果未能解决你的问题,请参考以下文章

NSString NSDictionary 和char *类型之间的转换

char[] 转换成cstring

如何在 C++ 中删除 char* [重复]

Java字符串中有多少个字符多少个char字节

用自身初始化一个字符串(C++)

C ++将字符串传递给lua错误