我无法理解,当文本大小相等时,指针如何相同。好像firststringgobj::c_str()覆盖了前一个的指针。
#include <iostream>
#include <string>
#include <string>
#include <stdio.h>
std::string getConstCharAndModifyItWithANewString( const char* constchar )
{
std::string stringAtStack( constchar );
stringAtStack += "::isModified";
return stringAtStack;
}
int main()
{
const char* firstConstCharPointer = getConstCharAndModifyItWithANewString("Hi!").c_str();
std::string firstStringObj = "Hi+";
printf(" firstConstCharPointer(%s)(%p)nfirstStringObj(%s)(%p)nn", firstConstCharPointer,firstConstCharPointer, firstStringObj.c_str(), firstStringObj.c_str() );
}
输出:firstConstCharPointer(嗨+)(0 x4593eb8)firstStringObj(嗨+)(0 x4593eb8)
指针在您的平台上是相同的,因为firstConstCharPointer
是一个悬空指针,它指向已释放的内存。
这是因为getConstCharAndModifyItWithANewString
返回的std::string
在赋值表达式const char* firstConstCharPointer = ...;
之后被破坏了。
所以当你创建一个新的std::string
对象时,编译器选择使用与之前的std::string
对象相同的内存位置,所以指针是相同的。
例如,在我的平台上,指针是相同的,它们不在Ideone中。
您有典型的未定义行为。printf
试图解除firstConstCharPointer
的保护,因为%s
。firstConstCharPointer
指向已经被销毁的数据,因为与此指针相关的std::string
在赋值后停止生存期:
const char* firstConstCharPointer = getConstCharAndModifyItWithANewString("Hi!").c_str();
// temporary std::string returned from getConstCharAndModifyItWithANewString destroyed, pointer becomes dangling.
如文档中所述:
从c_str()中获得的指针可能会被以下方式无效:
- 将字符串的非const引用传递给任何标准库函数,或者
- 在字符串上调用非const成员函数,不包括操作符[]、at()、front()、back()、begin()、rbegin()、end()和rend()。
因此使用了无效指针,因为析构函数是非const成员函数,上面没有列出。
你的函数返回一个临时 std::string
对象。在firstConstCharPointer
变量被赋值并且表达式完成之后,该临时对象被销毁,释放其分配的内存块,并使变量指向已释放的内存。这被称为悬空指针。
firstStringObj
分配一个新的内存块,碰巧重用了临时std::string
之前分配和释放的内存块。因此悬空指针恰好现在又指向有效内存。这就是为什么你的printf()
语句能够为两个字符串显示相同的内存地址和内容。
但这是未定义行为。每次分配的内存块完全由字符串的Allocator
来决定。第二个std::string
可以很容易地分配一个完全不同的内存块,然后代码将更有可能崩溃,或者至少打印垃圾,当它试图解引用仍然指向无效内存的悬空指针时。
为了使您的代码工作,您需要将firstConstCharPointer
更改为std::string
对象,以便正确复制临时std::string
,例如:
#include <iostream>
#include <string>
#include <cstdio>
std::string getConstCharAndModifyItWithANewString( const char* constchar )
{
std::string stringAtStack( constchar );
stringAtStack += "::isModified";
return stringAtStack;
}
int main()
{
const std::string firstConstStringObj = getConstCharAndModifyItWithANewString("Hi!");
std::string secondStringObj = "Hi!";
std::printf(" firstConstStringObj(%s)(%p)nsecondStringObj(%s)(%p)nn", firstConstStringObj.c_str(), firstConstStringObj.c_str(), secondStringObj.c_str(), secondStringObj.c_str());
}