C ++在作用域结尾之前删除函数指针

时间:2018-12-15 03:04:16

标签: c++ scope function-pointers destructor

如果我有功能:

std::string returnString() {
    return "Hello, World!";
}

通话:

std::string hello = returnString();
std::cout << hello << std::endl;

产生Hello, World!

但是,如果我尝试:

const char* hello = returnString().c_str();

,然后尝试使用:

for (const char* p = hello; *p; ++p ) {
    std::cout << *p;
}
std::cout << std::endl;

给我一​​个错误,说Invalid read of size 1,这意味着p是NULL

是什么原因导致这种行为?

感谢您的帮助。

1 个答案:

答案 0 :(得分:6)

(注意:我在这里掩盖了一些细节。如果您想知道我在这里提到的规则的例外情况,请查找“返回值优化”和“复制省略”。不要更改我在此描述的行为虽然回答)。

从函数返回对象时,返回的对象将在调用该函数的行的末尾销毁。情况总是如此。通常,您将像上一片段一样将该对象复制或移动到本地范围内的另一个对象中:

std::string hello = returnString();

在这一行中,returnString返回一个std::string对象,hello从返回的对象中进行移动构造,然后销毁原始对象。

如果您考虑稍微不同的一行,那就是出现问题了:

const char* hello = returnString().c_str();

在这种情况下,returnString返回一个std::string对象,您保存了一个指向该char对象所拥有的std::string数组的指针,然后是原始{{1} }对象被销毁,将您拥有一个指针的std::string数组作为对象。


char保留std::string返回的指针指向的char数组的所有权。 c_str会在其超出范围时删除其拥有的数组,这意味着指向的数组的生存期与std::string对象的生存期相关。

您可以认为std::string看起来像这样:

std::string

实际的class string { public: string(const char* str) : ptr_(new char[strlen(str) + 1]) { strcpy(ptr_, str); } ~string() { delete[] ptr_; } const char* c_str() { return ptr_; } // other members private: const char* ptr_; }; 有点复杂,但是基本思想是相同的。构造std::string对象时,它将分配一个std::string数组来保存字符串数据,而当char对象被破坏时,它将删除该数组。

std::string方法仅返回指向c_str内部std::string数组的指针。仅仅因为您有指向该数组的指针并不意味着在char对象死亡时也不会删除该数组,仅意味着您有一个指向不再拥有的内存的指针。