这怎么编译? (删除const对象的成员)

时间:2010-06-26 22:31:42

标签: c++

我希望复制构造函数中有一个错误,但这对MSVC10编译得很好。

class Test
{
public:
    Test()
    {
        p = new int(0);
    }

    Test(const Test& t)
    {
        delete t.p; // I would expect an error here
    }

    ~Test()
    {
        delete p;
    }

private:
    int* p;
};

4 个答案:

答案 0 :(得分:4)

这是指针的常见问题。实际上没有办法禁止代码在指针上调用delete(除了控制对析构函数的访问)。您可以听到的第一件事是delete不会修改指针,而是修改指向的对象。这可以通过在删除之前和之后打印指针(std::cout << static_cast<void*>(p);)来轻松检查,因此即使指针是常量,操作也不会修改

稍微不那么直观的是,您可以delete指向常量元素的指针 - 而delete肯定会修改指向的元素。但是当语言超出范围时,语言需要能够破坏常量对象(想象{ const mytype var(args); }),因此常量不能真正影响破坏对象的能力,如果允许自动变量,它就会改变动态分配对象的行为没有多大意义。所以最后也允许这样做。

答案 1 :(得分:3)

您遇到的问题是,您本身并未更改p(因此p保持不变,因为您没有更改其值),但您正在更改{ {1}}指向并因此在一个额外的间接层面工作。这是可能的,因为删除与指针关联的内存不会改变指针本身。

严格意义上说,即使在从p指向的任何p下面拉出地毯时,也会保留其逻辑常量,从而保留对象的常量。

正如JonH在评论中提到的那样,如果你无法删除const对象中保存的指针所指向的对象,那么最终会导致内存泄漏,因为你无法在对象

答案 2 :(得分:2)

常量是不可变的,但这并不能保证它们不能被删除。如果不允许删除,你将如何删除对象。

如果你试图修改应该抛出错误的t.p,因为t是const。但删除t是很正常的,即使它是恒定的。

答案 3 :(得分:0)

有:

int* const p;

...不禁止在 p 上调用operator delete。 const int*也不允许在其上调用operator delete。

典型的运算符删除实现采用void *并且任何指针都将被隐式地转换为它(实际上这可能是采用void *的标准行为,或者是实现一个可以删除任何内容的全局运算符delete的唯一合理方法)。另外,作为一个有趣的小工具,可以实现自己的重载操作符删除(全局或每个类),它取出void *并且只需释放new分配的内存。在编译器调用operator delete之前隐式添加析构函数调用; operator delete不会在其实现中调用dtor。

值得注意的是,在这种情况下const Test&基本上会修改成员int* p,使其类似于int* const p,而不是int const* p或{{1} }。

因此:

const int* p

换句话说,指针地址是不可变的,但指针不是。关于成员函数constness及其对作为指针的数据成员的影响,我经常遇到很多困惑。理解这一点将对我们需要在iterator和const_iterator之间进行分离的原因之一提供一些见解。