string my_string="My_First_Text";
char * my_pointer=(char *)(my_string+"My_Second_Text").c_str();
为什么?当我初始化my_pointer
时,我认为不需要my_pointer=new char[100]
。如果这个假设不成立,那么为什么?
string my_string="My_First_Text";
char * my_pointer=(char *)(my_string+"My_Second_Text").c_str();
为什么?当我初始化my_pointer
时,我认为不需要my_pointer=new char[100]
。如果这个假设不成立,那么为什么?
my_string+"My_Second_Text"
是一个临时的std::string
,在表达式执行完之后将被销毁。这意味着my_pointer
会立即变为悬空指针,因为它应该指向的字符数组已经随着临时std::string
的销毁而被销毁;请注意,返回的字符数组属于std::string
,它不是独立的。然后,在悬挂的指针上解除引用将导致未定义行为。string my_string="My_First_Text";
char * my_pointer=(char *)(my_string+"My_Second_Text").c_str();
// the temporary constructed from my_string+"My_Second_Text" has been destroyed
// my_pointer is dangled now; deference on it is UB
string my_string = "My_First_Text";
my_string += "My_Second_Text";
const char * my_pointer = my_string.c_str();
顺便提一下:std::basic_string::c_str的返回类型是const char*
,对其进行任何修改都是未定义行为。因此,试图显式将其转换为char*
是危险的。
尝试写入通过
c_str()
访问的字符数组是未定义行为。
int i=2; const int *cip; cip = &i; int* ip; ip = const_cast<int*>(cip); *ip = 4;
是可以的。 - Peter - Reinstate Monicastd::string
。无论如何,std::basic_string::c_str 表示返回的数组不应被修改。 "通过 c_str() 访问的字符数组的写入是未定义行为。" - songyuanyaoconst char * my_pointer
来解决这个问题,而不是使用char* my_pointer
?换句话说,通过使用const char * my_pointer
,我是否可以强制编译器将my_string +“My_Second_Text”
的结果存储在某个地方,并在;
结束时不销毁它? - Admiamy_pointer
指针随着临时std::string
的销毁而变得无效,这个事实并没有改变,所以仍然是未定义行为。 (UB意味着,即使在某些情况下似乎工作正常,但你根本不能依赖它。这只是C++世界中的怪物。) - songyuanyao(my_string+"My_Second_Text").c_str()
是一个临时值,在程序运行时会动态创建和销毁,不会被保存在内存中。
指向它会导致未定义的行为,因为所指向的内存未定义。对于字符串赋值到 char *
中,请使用 strcpy
或变量赋值,而不是临时值。
+
运算符返回一个新的临时字符串对象,该对象将在(my_string+"My_Second_Text").c_str()
表达式之外被销毁,因此对该字符串的任何引用都将悬空,并且通过它们访问的行为是未定义的。
c_str()
返回一个指向string
内部char数组的const指针。你不能且不应该通过该指针来操作string
。(my_string + "My_Second_Text")
的结果存储在一个新变量中,或使用append
函数将新字符串附加到现有字符串对象中。std::string new_string = my_string + "My_Second_Text";
const char* char_pointer = new_string.c_str();
my_string.append("My_Second_Text");
const char* char_pointer = my_string.c_str();
临时对象可能会引起晦涩的问题。
Bjarne C++ 书中相关摘录:
作为一个副注,C++中应该使用适当的类型转换而非C风格的类型转换。阅读以下链接:何时应该使用static_cast、dynamic_cast、const_cast和reinterpret_cast?
void f(string& s1, string& s2, string& s3) { const char∗ cs = (s1+s2).c_str(); // << Code similar to OP's example cout << cs; if (strlen(cs=(s2+s3).c_str())<8 && cs[0]=='a') { // cs used here } }
Probably, your first reaction is ‘‘But don’t do that!’’ and I agree. However, such code does get written, so it is worth knowing how it is interpreted.
A temporary string object is created to hold
s1 + s2
. Next, a pointer to a C-style string is extracted from that object. Then – at the end of the expression – the temporary object is deleted. However, the C-style string returned byc_str()
was allocated as part of the temporary object holdings1 + s2
, and that storage is not guaranteed to exist after that temporary is destroyed. Consequently, cs points to deallocated storage.The output operation
cout << cs
might work as expected, but that would be sheer luck. A compiler can detect and warn against many variants of this problem.