7

I'm a bit newbie to CPP and I don't know why the setValue() const works meanwhile it's a const.

Why the class allows modification from a const public

It seems really odd, there is no error on g++ -Wall or with MS Visual C++

Here is my code:

main.cpp

#include <iostream>
#include <cassert>
#include "DArray.h"

int main(void)
{
    DArray darray(1);
    darray.setValue(0, 42);
    assert(darray.getValue(0) == 42);
    darray.~DArray();
    system("pause");
    return 0;
}

DArray.h

class DArray
{
private:
    int* tab;

public:
    DArray();
    DArray(unsigned int n);
    ~DArray();

    int& getValue(unsigned int n) const;
    void setValue(unsigned int n, int value) const;
};

DArray.cpp

#include "DArray.h"

DArray::DArray()
{

}

DArray::DArray(unsigned int n)
{
    tab = new int[n];
}

DArray::~DArray()
{
    delete[] tab;
    tab = nullptr;
}

int& DArray::getValue(unsigned n) const
{
    return tab[n];
}

void DArray::setValue(unsigned n, int value) const // HERE
{
    tab[n] = value;
}
  • 6
    Why are you manually calling the destructor? Don't you know it will automatically be called when the object goes out of scope? – Some programmer dude Feb 16 '18 at 10:13
  • 10
    the pointer is const but it points to a non-const int – 463035818_is_not_an_ai Feb 16 '18 at 10:13
  • Your const-qualified function does not modify class. Note that `const` only prevent you from assigning a new value to `tab` pointer, that is makes `tab` a `const pointer`, but does not make `tab` a pointer to `const` so data pointer to by `tab` can still be modified. – user7860670 Feb 16 '18 at 10:14
  • 4
    the solution is to stop using raw (owning) pointers now. Use `std::vector` and dont mess around with calling `new` and `delete` in places where they dont belong – 463035818_is_not_an_ai Feb 16 '18 at 10:15
  • 1
    About the double deletion problem: add some output to your destructor and run the program to see; side note: deleting a `nullptr` is fine, this is why you do not get any further problems in this concrete case; deleting a *dangling* pointer, however, is fatal; drop `tab = nullptr;` from your destructor and your program is very likely to crash! On the other hand, if you do deletion correctly (in this case: just let the object run out of scope), you can drop this line anyway, as the object won't be there any more and it does not matter what the then unused space in memory is occupied with... – Aconcagua Feb 16 '18 at 10:40
  • 2
    Aside - you may wish to look up the keyword 'mutable' for when you can actually modify members of a class in a const fn. – UKMonkey Feb 16 '18 at 10:43
  • 1
    I might assume you made the setter const to illustrate your question only; still, to make it clear: A setter is intended to modify the class; although in your case, it did not *technically* (see the answers), however, it did so *semantically*, so it should *not* be `const` anyway! – Aconcagua Feb 16 '18 at 10:48
  • Possible duplicate of [What can a 'const' method change?](https://stackoverflow.com/questions/6852717/what-can-a-const-method-change) – xskxzr Feb 16 '18 at 11:24

3 Answers3

18

It is because you do not modify it. When you do:

int* tab

tab contains only an address. Then in

void DArray::setValue(unsigned n, int value) const // HERE
{
    tab[n] = value;
}

You do not modify this address, you modify some memory after it. Thus you do not modify your class.

If instead, you used

std::vector<int> tab

You would have an error in setValue because you would modify an element of your class.

Light
  • 308
  • 2
  • 6
  • kudos for suggesting an `std::vector` instead of a C-style array. – YSC Feb 16 '18 at 10:22
  • @Aconcagua Seing tab[n], I expect the only use to be an array :) – Light Feb 16 '18 at 10:56
  • In addition I'd like to mention that the const qualified version of `int*` is `int * const` and not `int const *`. The const always comes after the thing it's "consting" (`const int` is a special case of `int const`). And the const decl of the method kind of "appends" a const to every member. Do some research on const-correctness when you have spare time and feel like it... – Martin B. Mar 06 '18 at 18:06
6

First of all, don't call explicitely the destructor of your class, this will be called when the variable goes out of scope automatically.

darray.~DArray();

What you are promising with const in the method is that the member variables will not be modified. The variable int* tab is a pointer to an int. With your setValue function you are not changing the address of the pointer (which is promised not to be changed by the final const in the signature of your method) but the int value pointed by it. This is fine.

However, if you change the pointer address, for example with tab = nullptr, you will see a compiler error like:

error: assignment of member 'DArray::tab' in read-only object

FrankS101
  • 2,112
  • 6
  • 26
  • 40
3

Why can I modify the class with a const function in C++11?

It is possible to modify mutable state of the object. It is technically also possible to modify the non-mutable state using const_cast, but it would be a bad idea to do so because if the object itself is const, then behaviour would be undefined.

That's however not what you do in this code.

why the setValue() const works meanwhile it's a const.

Because it doesn't modify any member of this. It modifies an array that is pointed by a pointer to non-const. Constness of a member function, or constness of the object is not transfer to an indirectly pointed object.

eerorika
  • 232,697
  • 12
  • 197
  • 326