如何防止成员函数返回的指针被删除?

How do I prevent deletion of a pointer returned by a member function?

本文关键字:指针 删除 返回 何防止 成员 函数      更新时间:2023-10-16

考虑下面的示例代码。类Data用于存储数据数组:为了简单起见,我选择使用vector<char>作为数据成员。然而,这些数据必须由一个外部例程处理,它需要一个指向数组第一个元素的指针,当然,还有这个数组的长度:出于这个原因,我还实现了get_data()get_length()函数。

class Data
{
public:
    Data(const char* sourcePtr, int sourceLength) : _data(sourcePtr, sourcePtr+sourceLength) { ; }
    const char* get_data() const { return &_data.front(); }
    int get_length() const { return _data.size(); }
    void print() const
    {
        vector<char>::const_iterator it;
        for(it = _data.begin(); it != _data.end(); ++it)
            cout << *it;
    }
private:
    vector<char> _data;
};
现在考虑下面的代码示例,它使用类Data
int main(int argc, char** argv)
{
    char* a = new char[4];
    a[0] = 'b';
    a[1] = 'y';
    a[2] = 't';
    a[3] = 'e';
    Data myData(a,4);
    delete[] a;
    myData.print();
    cout << endl;
    const char* aPtr = myData.get_data();
    // The following statement frees the memory allocated
    // for the data member of the class Data.
    delete[] aPtr;
    return 0;
}

上面的语句delete[] aPtr释放了为Data类的数据成员分配的内存。因此,当自动释放myData对象时,vector<char>的内容已经被手动释放,显然会出现错误SIGABRT

如何确保编译器将语句delete[] aPtr标记为错误?您应该如何修改类Data来实现这个目标?

处理这个问题最直接的方法是明确谁是指针的"所有者"。在我的c++时代,如果一个函数返回一个指针,函数的名字应该以"Create"开头,而不是"Get"。后来,在这种情况下,我们通常返回智能指针。

在c++中,你不需要显式地删除任何指针,而是将所有指针存储在一个智能指针中,当指针被销毁时,它将删除指针,这实际上一点也不难。

停止使用"裸" newdelete操作,将new包装在RAII类型中,除非您正在编写RAII类型的析构函数,否则不要使用delete

std::unique_ptr<char[]> a{ new char[4] };
a[0] = 'b';
a[1] = 'y';
a[2] = 't';
a[3] = 'e';
Data myData(std::move(a),4);

这段代码意味着数组的所有权被明确地赋予了智能指针,然后明确地转移给了Data对象。尝试delete数组将无法编译。

这并不能阻止用户以后使用delete[] aPtr,但是如果你养成了从不使用delete的习惯,除非在RAII类型的析构函数中,那么当有人在不应该使用delete的地方引入bug时,它就会变得非常明显,因为他们不拥有内存。

不要摆弄指针。如果你的代码的用户不愿意停止这样做,那么让他们以痛苦的方式学习。

你没有。newdelete不跟踪指针的所有者。那是你的工作。

你可以做的是复制指针所指向的数据。那么调用者对数组做什么就无关紧要了。你有自己的副本,假设你没有做一些愚蠢的事情,比如把它暴露给任何想要它的人,它是安全的。

或者,查看std::unique_ptrstd::shared_ptr。就内存管理而言,它们是新的热点;当你使用智能指针时,内存几乎可以自我管理。

写好文档。阻止其他程序员做傻事不是你的工作。