Can I use const in vectors to allow adding elements, but not modifications to the already added?

后端 未结 14 559
既然无缘
既然无缘 2020-12-01 04:54

My comments on this answer got me thinking about the issues of constness and sorting. I played around a bit and reduced my issues to the fact that this code:



        
相关标签:
14条回答
  • 2020-12-01 05:29

    You're going to need to write your own class. You could certainly use std::vector as your internal implementation. Then just implement the const interface and those few non-const functions you need.

    0 讨论(0)
  • 2020-12-01 05:29

    I've been thinking a bit on this issue and it seems that you requirement is off.

    You don't want to add immutable values to your vector:

    std::vector<const int> vec = /**/;
    std::vector<const int>::const_iterator first = vec.begin();
    
    std::sort(vec.begin(), vec.end());
    
    assert(*vec.begin() == *first); // false, even though `const int`
    

    What you really want is your vector to hold a constant collection of values, in a modifiable order, which cannot be expressed by the std::vector<const int> syntax even if it worked.

    I am afraid that it's an extremely specified task that would require a dedicated class.

    0 讨论(0)
  • 2020-12-01 05:31

    Compilation fails because push_back() (for instance) is basically

    underlying_array[size()] = passed_value;
    

    where both operand are T&. If T is const X that can't work.

    Having const elements seem right in principle but in practice it's unnatural, and the specifications don't say it should be supported, so it's not there. At least not in the stdlib (because then, it would be in vector).

    0 讨论(0)
  • 2020-12-01 05:34

    Using just an unspecialized vector, this can't be done. Sorting is done by using assignment. So the same code that makes this possible:

    sort(v.begin(), v.end());

    ...also makes this possible:

    v[1] = 123;

    0 讨论(0)
  • 2020-12-01 05:38

    I'm with Noah: wrap the vector with a class that exposes only what you want to allow.

    If you don't need to dynamically add objects to the vector, consider std::tr1::array.

    0 讨论(0)
  • 2020-12-01 05:40

    Types that you put in a standard container have to be copyable and assignable. The reason that auto_ptr causes so much trouble is precisely because it doesn't follow normal copy and assignment semantics. Naturally, anything that's const is not going to be assignable. So, you can't stick const anything in a standard container. And if the element isn't const, then you are going to be able to change it.

    The closest solution that I believe is possible would be to use an indirection of some kind. So, you could have a pointer to const or you could have an object which holds the value that you want but the value can't be changed within the object (like you'd get with Integer in Java).

    Having the element at a particular index be unchangeable goes against how the standard containers work. You might be able to construct your own which work that way, but the standard ones don't. And none which are based on arrays will work regardless unless you can manage to fit their initialization into the {a, b, c} initialization syntax since once an array of const has been created, you can't change it. So, a vector class isn't likely to work with const elements no matter what you do.

    Having const in a container without some sort of indirection just doesn't work very well. You're basically asking to make the entire container const - which you could do if you copy to it from an already initialized container, but you can't really have a container - certainly not a standard container - which contains constants without some sort of indirection.

    EDIT: If what you're looking to do is to mostly leave a container unchanged but still be able to change it in certain places in the code, then using a const ref in most places and then giving the code that needs to be able to change the container direct access or a non-const ref would make that possible.

    So, use const vector<int>& in most places, and then either vector<int>& where you need to change the container, or give that portion of the code direct access to the container. That way, it's mostly unchangeable, but you can change it when you want to.

    On the other hand, if you want to be able to pretty much always be able to change what's in the container but not change specific elements, then I'd suggest putting a wrapper class around the container. In the case of vector, wrap it and make the subscript operator return a const ref instead of a non-const ref - either that or a copy. So, assuming that you created a templatized version, your subscript operator would look something like this:

    const T& operator[](size_t i) const
    {
        return _container[i];
    }
    

    That way, you can update the container itself, but you can't change it's individual elements. And as long as you declare all of the functions inline, it shouldn't be much of a performance hit (if any at all) to have the wrapper.

    0 讨论(0)
提交回复
热议问题