bomba6
bomba6

Reputation: 579

const pointer to const data and c++ lists

I want to insert some elements to the list.
What I really want to do is to use "insert3" because it guarantee that the pointer won't change, and the data won't change.
But "insert2" and "insert3" give the following error, which "insert1" doesn't:

class A
{
public:
    std::list<int*> l;
    void insert(int* const a)
    {
        l.push_back(a); //works
    }

    void insert2(const int* a)
    {
        l.push_back(a);
        /*
        no instance of overloaded function "std::list<_Ty, _Ax>::push_back [with _Ty=int *, _Ax=std::allocator<int *>]"
            matches the argument list
        */
    }

    void insert3(const int* const a)
    {
        l.push_back(a);
    }

};

Thanks for your help!

Upvotes: 2

Views: 3393

Answers (3)

AnT stands with Russia
AnT stands with Russia

Reputation: 320571

It is one of the typical higher-level "issues" with C++-style compile-time const-correctness type system.

If you want to store int * pointers in your list, then you will not be able to add const int * pointers to that list (for obvious reasons). This will allso force all your insert methods to accept int * pointers, not const int * pointers.

I understand, that what you really want to express is that insert method itself does not change the pointed data (and it doesn't). However, as you can see, insert has some far-reaching side-effects - it stores the pointer in a list. This would potentially violate the const-correctenss if insert accepted const int * pointers.

In other words, it is not enough to consider what insert is doing by itself, it is also important to consider what possibilities insert opens to other code (in this case - to other code that has access to the same list). And in your case the possibilities it opens would easily allow const-correcness violations in other code if your insert quietly accepted const int * pointers.

You can, of course, impose your own vision of proper const-correctness in this case by using forceful const_casts. But it won't look pretty.

Upvotes: 1

danielschemmel
danielschemmel

Reputation: 11126

Short answer

You should use a list<int const* const> as the type of l instead and then you can use any of your inserts including insert3.

Long answer

By inserting into a list<int*> you attempt to convert your int const* (pointer to const int) to an int* (pointer to int).

Since you are removing the guarantee that you will not edit the target of the pointer, this is not implicitly doable. You may use a const_cast (or c-cast) if you really wish to do this, but usually casting away const-ness is a very bad idea (tm).

Why making the pointer itself const won't change a thing

If you use version 3 using an int const* const (const pointer to const int), you are not getting anything more or less than the guarantee that the variable a will not be changed while insert3 is running. By inserting the pointer into your list, you are actually copying it. This means that no matter whether a is const or not, your resulting list item will be the type you specified in the beginning.

By making the list into list<int const* const> you ensure that any pointer inserted cannot be changed later on, and the value pointed to it can only be changed after explicitly getting rid of the constness of your pointer. Inserting into it is possible, since adding const is always implicitly possible

Upvotes: 2

David G
David G

Reputation: 96810

Change the list to take a pointer to const:

std::list<const int*> l;

Since you had a pointer to const for the parameter, taking away its const-ness through an implicit conversion wouldn't be allowed.

Upvotes: 1

Related Questions