doyoubi
doyoubi

Reputation: 153

In c++, if a member pointer point to some data, how to protect that data from being modified?

class A
{
public:
    A(){ val = 0; p = new int; *p = 0; }
    //void fun_1()const{ val = 1; }  not allowed
    void fun_2()const{ *p = 1; }
    void display()const{ cout<< val <<' '<< *p <<endl; }
private:
    int val;
    int * p;
};

int main()
{
    const A a;
    a.fun_2();
}

Change member data in a const member function like fun_1()const is not allowed. However, when the data is not directly the member of the object, but is allocated storage and assigned inside a object, const function can't protect it. fun_2()const can change the data which p point to although it's a const function for example.

Is there any way to protect the data which p point to ?

Upvotes: 1

Views: 164

Answers (4)

4pie0
4pie0

Reputation: 29724

just declare a pointer to constant:

const int * p;


void fun_2()const{ *p = 1; } // main.cpp:36: error: assignment of read-only  
                                // location ‘*(const int*)((const B*)this)->B::p’

In this case the integer pointed to by p cannot be changed at all, regardless if it is done ifrom a const or non-const function body. If you want still to be able to change the value of int from non-const member function you must not expose a pointer outside the class, make pointer private and use it accordingly.

Upvotes: 2

Ben Voigt
Ben Voigt

Reputation: 283614

It's relatively straightforward to cause the compiler to protect the pointed-to object, but this is not done automatically because it isn't always the correct thing to do.

template<typename T>
class constinator_ptr
{
    T* p;
public:
    explicit constinator_ptr( T* p_init ) : p (p_init) {}

    T*& ptr() { return p; } // use this to reassign, or also define operator=(T*)

    T* operator->() { return p; }
    const T* operator->() const { return p; }
    T& operator*() { return *p; }
    const T& operator*() const { return *p; }
};

Just use this in place of your raw pointer, like this:

class A
{
public:
    A() : val{0}, p{new int(0)} {}
    //void fun_1()const{ val = 1; }  not allowed
    void fun_2()const{ *p = 1; } // now causes error
    void display()const{ cout<< val <<' '<< *p <<endl; }
private:
    int val;
    constinator_ptr<int> p;
};

Upvotes: 3

Stack Overflow is garbage
Stack Overflow is garbage

Reputation: 247909

Just write your member functions so that they do not allow the caller to modify the object. As long as the pointer is private, whatever it points to can only be seen by other member functions. If you don't expose a member function which changes the pointed-to object, then it can't be changed by users of your class.

Note that you can declare the member as a "pointer to const" (which is not the same as a const pointer).

int const* p is a pointer to a const int (the pointer can be changed, but the int it points to cannot), whereas int* const is a const pointer to int (the pointer cannot be changed -- it always points to the same int, but the value of that int can be changed). And of course, a int const* const is a const pointer to a const int. Neither the pointer nor the int can be modified.

However, this won't really help you with enforcing that "const member functions should not modify the pointed-to object, but non-const member functions can" (because a pointer to a const int will always point to a const int, even if used from a non-const member function)

Upvotes: 2

n. m. could be an AI
n. m. could be an AI

Reputation: 119847

An easy and general solution is your own smart pointer class with deep-const semantics. Just wrap a plain pointer in deepconst<T>, add const T* operator->() const and const T& operator*() const to the usual non-const versions, and you sre done.

Upvotes: 2

Related Questions