std::string::c_str() 覆盖函数返回的前一个
std::string::c_str() overwrittes the previous one returned by a function
我不明白,当文本大小相等时,指针怎么可能相同。似乎 firstStringObj::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)\n\n", firstConstCharPointer,firstConstCharPointer, firstStringObj.c_str(), firstStringObj.c_str() );
}
输出:
firstConstCharPointer(高+)(0x4593eb8)
firstStringObj(Hi+)(0x4593eb8)
指针在您的平台上是相同的,因为 firstConstCharPointer
是一个悬挂指针,它指向已释放的内存。
那是因为getConstCharAndModifyItWithANewString
返回的std::string
在赋值表达式const char* firstConstCharPointer = ...;
后被销毁了。
所以当你创建一个新的 std::string
对象时,编译选择使用与之前的 std::string
对象相同的内存位置,所以指针是相同的。
例如在我的平台上,指针是相同的,它们不在 Ideone。
您有典型的未定义行为。由于 %s
,printf
试图取消对 firstConstCharPointer
的引用。 firstConstCharPointer
指向已被销毁的数据,因为与此指针的生命周期关联的 std::string
在赋值后停止:
const char* firstConstCharPointer = getConstCharAndModifyItWithANewString("Hi!").c_str();
// temporary std::string returned from getConstCharAndModifyItWithANewString destroyed, pointer becomes dangling.
所述
The pointer obtained from c_str() may be invalidated by:
- Passing a non-const reference to the string to any standard library function, or
- Calling non-const member functions on the string, excluding operator[], at(), front(), back(), begin(), rbegin(), end() and rend().
所以你使用了无效的指针,因为析构函数是一个非常量成员函数,没有在上面列出。
您的函数 returns 一个 临时 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)\n\n", firstConstStringObj.c_str(), firstConstStringObj.c_str(), secondStringObj.c_str(), secondStringObj.c_str());
}
我不明白,当文本大小相等时,指针怎么可能相同。似乎 firstStringObj::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)\n\n", firstConstCharPointer,firstConstCharPointer, firstStringObj.c_str(), firstStringObj.c_str() );
}
输出: firstConstCharPointer(高+)(0x4593eb8) firstStringObj(Hi+)(0x4593eb8)
指针在您的平台上是相同的,因为 firstConstCharPointer
是一个悬挂指针,它指向已释放的内存。
那是因为getConstCharAndModifyItWithANewString
返回的std::string
在赋值表达式const char* firstConstCharPointer = ...;
后被销毁了。
所以当你创建一个新的 std::string
对象时,编译选择使用与之前的 std::string
对象相同的内存位置,所以指针是相同的。
例如在我的平台上,指针是相同的,它们不在 Ideone。
您有典型的未定义行为。由于 %s
,printf
试图取消对 firstConstCharPointer
的引用。 firstConstCharPointer
指向已被销毁的数据,因为与此指针的生命周期关联的 std::string
在赋值后停止:
const char* firstConstCharPointer = getConstCharAndModifyItWithANewString("Hi!").c_str();
// temporary std::string returned from getConstCharAndModifyItWithANewString destroyed, pointer becomes dangling.
The pointer obtained from c_str() may be invalidated by:
- Passing a non-const reference to the string to any standard library function, or
- Calling non-const member functions on the string, excluding operator[], at(), front(), back(), begin(), rbegin(), end() and rend().
所以你使用了无效的指针,因为析构函数是一个非常量成员函数,没有在上面列出。
您的函数 returns 一个 临时 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)\n\n", firstConstStringObj.c_str(), firstConstStringObj.c_str(), secondStringObj.c_str(), secondStringObj.c_str());
}