使用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
所有印刷 name
而 std::string
版本是否能正常工作?
有什么方法可以让我修改 string_from_env
函数,这样同样的代码就会打印出 host user name
而不是 name name name
?
答案
返回的指针 std::string::c_str
指的是该公司所拥有的内存。string
对象。 当 string
被破坏(甚至以某种方式变异),该指针就会失效。
由于临时的 string
返回的对象 string_from_env
中的前三个调用并没有立即绑定到引用上,而是在包含函数调用的完整表达式结束时被销毁。 这意味着 x1
, x2
和 x3
都会在创建后立即失效。 试图从它们中读取数据将导致未定义的行为。
另一答案
考虑这一行
const char* x1 = string_from_env("TEST_HOST").c_str();
你不存储调用 string_from_env("TEST_HOST")
所以它返回的临时字符串将在表达式结束时被销毁。所以 x1
将指向一个已经销毁的字符串的内部缓冲区。你的代码有未定义的行为。
原因是 x1
, x2
和 x3
都指向同一个字符串,这与小字符串优化有关,这是std::string的一个实现细节。
以上是关于使用std::getenv时,char*和string之间的意外差异。的主要内容,如果未能解决你的问题,请参考以下文章