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

时间:2013-03-05 21:31:38

标签: c++ arrays oop pointers

考虑下面的示例代码。类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以实现此目标?

4 个答案:

答案 0 :(得分:6)

解决这个问题最直接的方法是确保谁是指针的“拥有者”。在我的C ++时代,如果一个函数返回一个指针,那么该函数的名称应该以“Create”而不是“Get”开头。之后,我们通常会在这种情况下返回智能指针。

实际上编写C ++并不困难,你永远不需要显式地删除任何指针,而是将它们全部存储在一个智能指针中,当指针被自身销毁时它将被删除。

答案 1 :(得分:4)

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

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的地方引入错误时,显然,因为他们没有内存。

停止摆弄裸指针。如果您的代码的用户不会停止这样做,那么让他们学习很难。

答案 2 :(得分:1)

你不是。 newdelete不跟踪谁拥有指针。这是你的工作。

您可以做的是复制指针指向的数据。那么调用者对其数组的作用并不重要。你拥有自己的副本,并假设你没有做任何像暴露给任何想要它的人那样的脑卒中,那就安全了。

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

答案 3 :(得分:1)

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