0

I have looked at the following threads but they don't talk about the constness of address returning functions:

(1) Returning a pointer to a vector element in c++

(2) It's safe to return address of a std::map value?

In the code:

class test_c{
    private: 
        std::vector <double> dblvec;
        double *dblarray;
    public:
        double *AddVecElem(int index){return &dblvec[index];} //Fine
        double *AddVecElem(int index) const {return &dblvec[index];} //compiler error "Return value type does not match function type"
        double *AddArrElem(int index){return &dblarray[index];}//Fine
        double *AddArrElem(int index) const {return &dblarray[index];}//Fine
};

Only the case where returning the address of a vector element's address as a const function produces a compiler error.

Why is this? How can returning the address of a vector element affect the state of the object?

Tryer
  • 3,580
  • 1
  • 26
  • 49
  • _"How can returning the address of a vector element affect the state of the object?"_ -- Because you can indirectly modify the vector through the pointer which points to a *non-const* element. Fix this by returning `double const*` from the `const` functions. – zett42 Sep 29 '18 at 13:50
  • @zett42 would that not be the case with `const` function returning the array double also? – Tryer Sep 29 '18 at 13:52

2 Answers2

3

Because dblvec[index] in a const function would call:

const_reference operator[]( size_type pos ) const;

And as of that &dblarray[index] is of the type const double *, and this cannot be converted to double *.

dblarray[index] on the other hand is a double so you return a double *

Check the question What can a 'const' method change? for more details about what is const if you are within a const function.

t.niese
  • 39,256
  • 9
  • 74
  • 101
  • Between `double* AddArrElem(int) const{}` and `double* AddArrElem(int) {}` when should one prefer the former vs the latter? – Tryer Sep 29 '18 at 14:02
  • @Tryer it is not really clear what the `AddVecElem` element should do. In general you should avoid c style arrays like `double *dblarray` and use std containers instead. And use `const` member functions whenever you want to make clear (an ensure through the compiler) that calling that function won't change the object or its memeber in any way. – t.niese Sep 29 '18 at 14:07
  • I agree with that. But still, my question is, what does `double* AddArrElem(int) {}` allow one to do with the returned address, which is not possible with `double* AddArrElem(int) const {}`. – Tryer Sep 29 '18 at 14:54
  • @Tryer for `double* AddArrElem(int)` and `double* AddArrElem(int) const` there is no difference what one could do with the returned pointer, both have the same type with the same constness. It has a different meaning for the reader `double* AddArrElem(int) const {}` indicates that calling this function would not result in any - for the caller relevant - changes, so for the caller it should be as if nothing has changed. But if you return `double *` from your `const` member function then this prevents the compiler to check if this is ensured. – t.niese Sep 29 '18 at 15:10
3

If you declared function as class const function, what means that you can't change the class's variables from the function, you can't return an address of class's variable, unless you'll promise that this function returns a non-changeable (const) value.

Inside the const function, the function looks at the class's variables as const variables, so when you try to return the address, you actually return const double * and not double * as the function requires.

The solution for this case is to return a pointer to const T:

const double* AddVecElem(int index) const {return &dblvec[index];}

Or, as you mentioned to declare this function as non-const function.

Another solution is to return a non-pointer value (copy of the value), and use void setValue(..) function to change this class's variable data.

As for double *dblarray your function doesn't returns the pointer itself, it returns a copy of your variable (pay attention- your function returns double* and the variable is within the same pointer level- so it returns a copy). It is just like the following example:

private:
    int value;
public:
    int return_value() const {
        return value; // Copy of the const returns - you don't change class's variable data
    }
    int* return_pointer_value() const {
        return &value; // Compiler error - expected int* returns const int*
    }

So, if you want to make the pointer situation equals to the vector's one, you should return double** and not double*:

double **AddArrElem(int index) const {
    return &dblarray; // Compiler error - expected double** returns const double *const*
    // (*const)=> for 'dblarray', (*)=> for '&'
}

Then why the vector behave differently? Why you can't returns &dblvec[index]? As mentioned in @t.niese post, the call to the operator function of vector recognize that it's a const vector, so it automatically returns const double- let's have a look of this function:

double& AddVecElem(int index) const {
    return dblvec[index]; // Compiler error - Expected double returns const double
}

We want to return reference to this variable, but the returned variable is a constant. So when you want to return double* you actually returns const double*.

Even when you try to go around and call to vector.data() it returns you const double * instead of double* - And this is the difference between the vector and the pointer.

As reference: Can const member function return a non-const pointer to a data member?

Swordfish
  • 12,971
  • 3
  • 21
  • 43
Coral Kashri
  • 3,436
  • 2
  • 10
  • 22
  • The error returned by `&dblarray` is not the same error as the one of `&dblvec[index]`. `&dblarray` is a `double* const*` (the member `dblarray` of the object is const and cannot be changed), `&dblvec[index]` is a `const double*` (the value in the vector cannot be changed). A `return dblarray` which is equal to `dblarray[0]` is still possible. The reason for that is that the `const` member function only requires that the value `dblarray` holds (the memory address) must not be changed, but this limitation is not true for its content. – t.niese Sep 29 '18 at 14:17
  • Thank you for the post and the effort. This is very helpful. – Tryer Sep 29 '18 at 17:08