C++在范围结束前删除函数指针

jac*_*111 2 c++ destructor scope function-pointers

如果我有一个功能:

std::string returnString() {
    return "Hello, World!";
}
Run Code Online (Sandbox Code Playgroud)

电话:

std::string hello = returnString();
std::cout << hello << std::endl;
Run Code Online (Sandbox Code Playgroud)

生产Hello, World!.

但是,如果我尝试:

const char* hello = returnString().c_str();
Run Code Online (Sandbox Code Playgroud)

并尝试打印:

for (const char* p = hello; *p; ++p ) {
    std::cout << *p;
}
std::cout << std::endl;
Run Code Online (Sandbox Code Playgroud)

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

是什么导致了这种行为?

谢谢你的帮助.

Mil*_*nek 6

(注意:我在这里浏览一些细节.如果你想知道我在这里提到的规则的例外情况,请查看返回值优化和复制删除.虽然不改变我在这个答案中描述的行为) .

从函数返回对象时,返回的对象在调用函数的行的末尾被销毁.这是的情况.在名义上,您将该对象复制或移动到本地范围内的另一个对象中,如上一个代码段所示:

std::string hello = returnString();
Run Code Online (Sandbox Code Playgroud)

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

如果你考虑一个稍微不同的线,就会出现问题:

const char* hello = returnString().c_str();
Run Code Online (Sandbox Code Playgroud)

在这种情况下,returnString返回一个std::string对象,你保存一个指向charstd::string对象所拥有的数组的指针,然后原始std::string对象被销毁,char带有一个指针的s 数组.


std::string保留char由返回的指针指向的s 数组的所有权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_;
};
Run Code Online (Sandbox Code Playgroud)

真实std::string有点复杂,但基本思路是一样的.当std::string对象被构造,它分配的阵列chars到保持字符串数据,并且当所述std::string对象被销毁它会删除该阵列.

c_str方法只返回指向std::string内部char数组的指针.只是因为你有一个指向该数组的指针并不意味着当std::string对象死亡时它不会被删除,它只是意味着你有一个指向你不再拥有的内存的指针.