tags:

views:

116

answers:

6

I apologize if this has been asked, but how do I create a member function in c++ that returns a pointer in the following scenerios: 1. The returned pointer is constant, but the junk inside can be modified. 2. The junk inside is constant but the returned pointer can be modified. 3. Neither the junk, nor the pointer can be modified.

Is it like so:

  1. int *const func() const
  2. const int* func() const
  3. const int * const func() const

All of the tutorials I've read don't cover this distinction.

Side note: If my method is declared const then the tutorials say that I'm stating that I won't modify the parameters.. But this is not clear enough for me in the case when a parameter is a pointer. Do my parameters need to be like:

a. void func(const int* const x) const;
b. void func(const int* x) const;
c. void func(const int* const x) const;

Thanks in advance!

+4  A: 

I don't know what book you have read, but if you mark a method const it means that this will be of type const MyClass* instead of MyClass*, which in its turn means that you cannot change nonstatic data members that are not declared mutable, nor can you call any non-const method.

Now for the return value.

1 . int * const func () const

The function is constant, and the returned pointer is constant but the 'junk inside' can be modified. Howerever I see no point in returning a const pointer because the ultimate function call will be an rvalue, and rvalues of non-class type cannot be const, meaning that const will be ignored anyway

2 . const int* func () const

This is a useful thing

3 . const int * const func() const

semantically almost the same as 2, due to reasons in 1.

HTH, Armen.

Armen Tsirunyan
I think you have a couple pieces of useful information in this reply, but my question still remains.. If I make a member method const, what am I *required* to have as my method signature. I apologize if I'm not understanding you
Jor
@Jor: You're not _required_ to make any restrictions on the rest of the function signature. The only thing to note is that in a `const` method `this` is a pointer to `const` so if you return a member by pointer or reference the either return value would have to be reference or pointer to a `const` type or you would have to do a potentially dangerous `const_cast`.
Charles Bailey
@Jor: Which is to say, the return type depends on what you're returning. If you're returning the address of a class member, then that member is const within a const member function, so you'd want option (2).
Ben Voigt
+1  A: 

Some uses of const don't really make much sense.

Suppose you have the following function:

void myFunction (const int value);

The const tells the compiler that value must not change inside the function. This information does not have any value for the caller. It's up to the function itself to decide what to do with the value. For the caller, the following two function definitions behave exactly the same for him:

void myFunction (const int value);
void myFunction (int value);

Because value is passed by value, which means that the function gets a local copy anyway.

On the other hand, if the argument is a reference or a pointer, things become very different.

void myFunction (const MyClass &value);

This tells the caller that value is passed by reference (so behind the screens it's actually a pointer), but the caller promises not to change value. The same is true for pointers:

void myFunction (const MyClass *value);

We pass a pointer to MyClass (because of performance reasons), but the function promises not to change the value.

If we would write the following:

void myFunction (MyClass * const value);

Then we are back int he first situation. myFunction gets a pointer, which is passed by value, and which is const. Since MyFunction gets a copy of the pointer value, it doesn't matter for the caller whether it is const or not. The most important thing is that myFunction can change the contents of value, because the pointer variable itself is const, but the contents in it isn't.

The same is true for return values:

const double squareRoot(double d);

This doesn't make any sense. squareRoot returns a const double but since this is passed 'by value', and thus needs to be copied to my own local variable, I can do whatever I want with it.

On the other hand:

const Customer *getCustomer(char *name);

Tells me that getCustomer returns me a pointer to a customer, and I am not allowed to change the contents of the customer.

Actually, it would be better to make the char-pointer-contents const as well, since I don't expect the function to change the given string:

const Customer *getCustomer(const char *name);
Patrick
Okay, I'm beginning to understand Patrick, and I realized that a const method has to do with not modifying the class members.. So forget that. But I like your answer, so maybe you can answer these: In "const Customer *getCustomer(char *name);" you said that the caller cannot modify the result. But is it the case that they cannot modify the result through the returned variable, but if they copy that pointer over to another pointer they *can* modify the contents?
Jor
And here's another question. A const method can't return a pointer to it's class members unless it's a const pointer.. But what type of const pointer does it have to be? 1: const *int 2: const * const int 3: int * const
Jor
If you assign the return value of the "const Customer *getCustomer()" function to a "Customer *" variable, then you will be able to change the contents of Customer. However, the C++ compiler gives an error on this assignment, since you are normally not allowed to assign a const-pointer to a non-const-pointer, since this grants you 'additional rights' (namely: being able to change the contents of Customer). In some cases however (especially when dealing with older pure C code), you might need to circumvent this, and then you should use a const_cast.
Patrick
On your second question: the return value must be "const *int". Placing const just before int doesn't make sense, since the caller gets a copy of the pointer anyway, and telling it that it must not change the 'temporary' returned by the function doesn't make sense.
Patrick
@Jor hint: assuming you aren't casting away constness, the compiler will verify that you are obeying const declarations - it may be easiest to just *try* modifying variables (what they point to, as well as their contents), given different signatures in a function.
Justin
A: 

if you make a member method const, syntactically you have to add const after the closing parentheses of perameter list. Semantically, in that method you cannot call any member function on the same object which is NOT const, also you cannot change any nonstatic member which is not mutable. These are what the compiler will detect. However there are situations which you must be cautious of. FOr example, consider you have a pointer member p. In a const method, p will be a const pointer, but the junk modifyable (as in 1.) but you don't want to mark such a method const if you do change the junk because it does change your object's state, although the compiler can't see it.

Sorry if I misunderstand your question again. Can you be more specific please? Maybe an example might help?

Armen Tsirunyan
A: 

The const method prevents you from modifying the members. In case of pointers, this means you can't reassign the pointer. You can modify the object pointed at by the pointer to your heart's desire.

As the pointer is returned by value (a copy), the caller can't use it to modify the pointer member of the class. Hence adding const to the return value adds nothing.

Things are different if you were to return a reference to the pointer. Now, if the pointer weren't const, this would mean that a function that doesn't have rights to modify a value is granting this right to the caller.

Example:

class X
{
    int* p;
public:
    int* get_copy_of_pointer() const //the returned value is a copy of this->p
    { 
        *p = 42;  //this being const doesn't mean that you can't modify the pointee
        //p = 0;  //it means you can't modify the pointer's value
        return p; 
    }
    int* const& get_reference_to_pointer() const //can't return a reference to non-const pointer
    {
        return p;
    }
};
visitor
A: 

Returning a pointer to const makes a lot of sense, but returning a const pointer (you cannot modify) usually adds no value (although some say it can prevent user errors or add compiler optimisation).

That is because the return value belongs to the caller of the function, i.e. it is their own copy so it doesn't really matter if they modify it (to point to something else). The content however does not "belong" to the caller and the implementor of the function may make a contract that it is read-only information.

Const member functions promise not to change the state of the class, although this is not necessarily enforced in reality by the compiler. I am not referring here to const_cast or mutable members so much as the fact that if your class itself contains pointers or references, a const member function turns your pointers into constant pointers but does not make them pointers to const, similarly your references are not turned into references-to-const. If these are components of your class (and such components are often represented by pointers) your functions can change their state.

Mutable members are there for the benefit of allowing your class to change them whilst not changing internal state. These can typically be applied to:

  • Mutexes that you wish to lock even for reading.
  • Data that is lazy-loaded, i.e. filled in the first time they are accessed.
  • Reference-counted objects: You want to increase the reference count if it has another viewer, thus you modify its state just to read it.

const_cast is generally considered a "hack" and is often done when someone else has not written their code properly const-correct. It can have value though in the following situations:

  • Multiple overloads where one is const and one non-const and the const returns a const-reference and the non-const returns a non-const reference, but otherwise they are the same. Duplicating the code (if it is not a simple data member get) is not a great idea, so implement one in terms of the other and use const_cast to get around the compiler.

  • Where you want in particular to call the const overload but have a non-const reference. Cast it to const first.

CashCow
+2  A: 

int *const func() const

You cannot observe the const here except for a few cases

  • Taking the address of func.
  • In C++0x, directly calling func with the function-call syntax as a decltype operand, will yield int * const.

This is because you return a pure pointer value, that is to say a pointer value not actually stored in a pointer variable. Such values are not const qualified because they cannot be changed anyway. You cannot say obj.func() = NULL; even if you take away the const. In both cases, the expression obj.func() has the type int* and is non-modifiable (someone will soon quote the Standard and come up with the term "rvalue").

So in contexts you use the return value you won't be able to figure a difference. Just in cases you refer to the declaration or whole function itself you will notice the difference.

const int* func() const

This is what you usually would do if the body would be something like return &this->intmember;. It does not allow changing the int member by doing *obj.func() = 42;.

const int * const func() const

This is just the combination of the first two :)

Johannes Schaub - litb