Vector that can hold any POD - c++

Is there a sort of vector that can hold any POD? something like:
anyvector v;
v.push_back<int>(1);
v.push_back<somestruct>({1, 2, 3});
and access it with:
int a = v.get<int>(0);
somestruct b = v.get<somestruct>(1);
I know there must be an overhead to save the offsets of each element, but it should be less than the overhead of vector<boost::any> which is my current solution.
The operations I need is insertion to end, removal from end and random access.
I know its not a problem to implement one, just asking if there is a ready one.
Edit: A solution that uses pointers to store data (boost::any, boost::variant) is a big overhead over using linear storage which is what I'm looking for.

I've never heard of one, and I'd be surprised if one exists, given how
very special it is. It shouldn't be too hard to implement, however,
using two vectors, a std::vector<unsigned char> for the raw memory
where you put the objects, and std::vector<size_t> to map the indexes.
As long as it only contains POD's, you can use memcpy to insert the
elements. Just don't forget to respect alignment. And that the index
array maps indexes: don't try to put pointers into it, since these will
be invalidated by later push_back.
For that matter, it shouldn't be too hard to implement one which holds
any type, even non-PODs, using placement new and explicit destruction.
The only real problem would be alignment. When you insert into the
vector, you'ld have to also save an instance of a polymorphic destructor
type. This could be a little tricky, but is doable, at least in
practice. Basically, you'ld be duplicating what boost::any does, but
instead of the pointer to dynamic memory, you'd get the "dynamic memory"
from the second array.

std::vector<boost::variant<int,somestruct,...>> v;
v.push_back(1);
v.push_back(({1, 2, 3});
a = boost::get<int>(v[0]);
provided you know which types have to be handled at declaration.
-- edit
As JohannesD said boost::variant impacts the size of each element, but
as James Kanze said, maintaining a vector of offset is very similar to boost::any and I am not sure you can really be more compact.
Depending on your exact requirement, another solution may work for you.
Store internally a different container for each type, this may not be a lot better than directly using multiple vectors, but you can store extra information like the last few elements stored. and you still got everything in one place.
Something like :
template <template <class,class> class C, typename T, typename ...Args>
struct map_ { //FIXME: return a list of type C<T1>,C<T2>...
};
template <template <class...> class C, typename ...Args>
struct fill_ { // Hack to parametrize map by Args on GCC 4.6
typedef T<Args> type;
};
template <typename... Ts>
struct hvec
{
std::map<std::string,fill_<boost::variant,map_<std::vector,Ts>> vec_map;
std::size_t last_id;
std::string last_typeid;
template <typename T>
T get(std::size_t i)
{
std::vector<T>& v = vec_map[typeid(T).name];
return vec[i];
}
template <typename T>
std::size_t push_back(const T& e)
{
std::vector<T>& v = vec_map[typeid(T).name];
v.push_back(e);
}
};
Of course you could replace vectors by maps and thus remember elements id, this would fulfill your requirement but add extra costs and still implies one "address"/key by element. However in this case you will never have to remember the type of an element at a given offset.

So you don't want pointers: that means you need an element type big enough to directly contain any POD. Given that POD objects can have arbitrary size, this is obviously impossible.
If you have a set of candidate types, it seems like you can have a bounded-size discriminated union, but isn't that what Boost.Variant does? The documentation indicates it will be stack-based (so presumably inline) where possible. How did you measure this "big overhead"?

you could try soemthing like the combination of vector and pair
enum ElementType : unsigned int
{
ET_INT,
ET_WHATEVER
};
vector < pair < void*, unsigned int >* > v;
pair < void*, unsigned int > prv;
int i;
prv.first = &i;
prv.second = ET_INT;
v.push_back( &prv );
it would be your choice to store objects by reference or by value. access to singloe elements would be like that:
int a = *( int* ) v.at( 0 )->first
that would give you fixed vector element size and info on the type of every stored element. when storing objects by reference watch out for lifetimes and namespaces, but i prefer conversion from types and making sure that the void pointers are valid instead of passing hugh sized parameters to functions everytime.
hope it helps;)

A std::tuple can store a sequence of arbitrarily sized elements, but only a fixed set of them.
An arbitrary number of elements with arbitrary types at runtime sounds error prone and very unsafe. What do you expect to happen if you do the following?
anyvector v;
v.push_back<Foo>(Foo());
int i = v.back<int>();
You'd be lucky if the implementation could provide you with a runtime exception, and I don't think there's any way that an implementation of anyvector could guarantee that. For example, if it tried to use RTTI it would run into the problem that there's actually no guarantee that two type_info objects that refer to different types won't be equal.

I think to get the best approximation to what you want, you will need to build your own data structure. You can base your type off of two implementation types:
std::vector<unsigned char> blobStorage_;
std::vector<size_t> offsetMap_;
This is effectively a serialisation blob implementation with the ability to offset access individual objects serialised into the blob.
When you want to push_back an object, you
serialise it into the end of the blobStorage
add the offset (front of your new object's blob) into the offsetMap
Similarly when you want access element that you think of as vector[n], you
get the offset from offsetMap_[n]
deserialise the object as the supplied type from blobStorage_[offset]
Both of these operations are order O(sizeof(object)), but effectively constant.
Usually, though, when you want to do something like this, you do "actual" serialisation into a blob, where by "actual" I mean you actually design the serialisation into your program. This typically means that you use a standard header to the storage of your types that gives a type ID and potentially size information. The reason you would normally do this is because you lose the type information when you serialise, and in the usage pattern you have indicated (where the type is supplied in the get), you are building a very fragile program with a lot of unwritten contracts. You don't typically want your programs easy to break in a professional environment working with others. So you can make it much more robust by storing type ids and registering the types with their type ids inside a greater serialisation design. Then, the "vector" will know how to deserialise and present the correct type of object.

std::vector stores elements as a contiguous array
In such an array each element has a starting address sizeof(Elem) past the previous element
POD types may be arbitrarily large
There is no way to have a vector of arbitrarily large objects, because sizeof(Elem) is unlimited.
The answer, unless you can restrict yourself further, is simply no.
If you can set an upper size limit, then yes it is possible, without any overhead. POD objects can be used without explicit construction, or killed without explicit destruction. So you can just create a vector of std::array< char, N > and reinterpret_cast the elements to your desired type.
typedef std::vector< std::array< char, pod_size_max > > pod_variant_vector;
template< typename destination >
destination &get( pod_variant_vector &vec, std::size_t index )
{ return reinterpret_cast< destination & >( vec[ index ] ); }
template< typename destination >
destination const &get( pod_variant_vector const &vec, std::size_t index )
{ return reinterpret_cast< destination const & >( vec[ index ] ); }
Be sure not to use the value of any such object before it has been initialized using the same type you are getting.

Related

union instead of aligned_storage_t as part of node type of container

Containers std::list< T >/std::map< T >/std::set< T > (not full list) to store an elements uses node types, which differs from T, as opposite to, say, std::vector or std::array.
If I pass some allocator A to them, then it will be "converted" to node_allocator_type by means of something like:
using allocator_traits = typename std::allocator_traits< A >::template rebind_traits< node_type >;
using node_allocator_type = typename allocator_traits::allocator_type;
Standard library implementations (libc++, libstdc++) may use an analogue of std::aligned_storage_t< sizeof(T), alignof(T) > as a constituent of the node type as a place to store value of type T. "Past the end" or "root" elements may have no storage for a value of type T. Life circle of the value is "manually" managed by containers by means of using in-place ::operator new and manual calling of a destructor finally.
Is it valid to use single-element union in form
union U
{
U() { ; }
T value;
};
instead of std::aligned_storage_t< sizeof(T), alignof(T) >?
Which properties of std::aligned_storage_t (internally it may be implemented as a properly aligned array of type char [sizeof(T)];) are crucial in the mentioned use case and prevail over all potential advantages of the above union?
First, the closer analogue is actually:
union U
{
U() { }
~U() { }
T value;
};
in case T isn't trivially destructible.
That said, the union is going to be necessary when you want a literal type. Can't use placement-new in a constexpr constructor so that's out to start with. That's a big win in that direction.
One advantage of aligned_storage_t is that you don't need to worry the potential of T overloading operator&(). new (&u.value) T might do something weird and might not compile at all. new (&storage) T doesn't have that problem, while being more ergonomic than new (std::addressof(u.value)) T.

Why can we not access elements of a tuple by index?

tuple <int, string, int> x=make_tuple(1, "anukul", 100);
cout << x[0]; //1
cout << get<0>(x); //2
2 works. 1 does not.
Why is it so?
From Lounge C++ I learnt that it is probably because the compiler does not know what data type is stored at that index.
But it did not make much sense to me as the compiler could just look up the declaration of that tuple and determine the data type or do whatever else is done while accessing other data structures' elements by index.
Because [] is an operator (named operator[]), thus a member function, and is called at run-time.
Whereas getting the tuple item is a template mechanism, it must be resolved at compile time. Which means this can be only done with the <> templating syntax.
To better understand, a tuple may store different types. A template function may return different types depending on the index passed, as this is resolved at compile time.
The operator[] must return a unique type, whatever the value of the passed parameter is. Thus the tuple functionality is not achievable.
get<0>(x) and get<1>(x) are two different functions generated at compile time, and return different types. The compiler generates in fact two functions which will be mangled to something like
int get_tuple_int_string_int_0(x)
and
string get_tuple_int_string_int_1(x)
The other answers here address the issue of why this isn't possible to implement, but it's also worth asking the question of whether it should be possible. (The answer is no.)
The subscript operator [] is semantically supposed to indicate dynamically-resolved access to a element of a collection, such as an array or a list (of any implementation). The access pattern generally implies certain things: the number of elements probably isn't known to the surrounding code, which element is being accessed will probably vary at runtime, and the elements are all of the same observable type (thus, to the calling code, interchangeable).
Thing is, a tuple isn't (that kind of) a collection. It's actually an anonymous struct, and its elements aren't interchangeable slots at all - semantically, they are regular fields. What's probably throwing you off is that they happen to be labelled with numbers, but that's really just an anonymous naming pattern - analogous to accessing the elements as x._0, x._1, etc. (The fact you can compute the field names at compile-time is a coincidental bonus enabled by C++'s type system, and is not fundamentally related to what a tuple is; tuples, and this answer, are not really specific to C++.)
So it doesn't support operator[] for the same reason that plain old structs don't support operator[]: there's no semantically-valid use for it in this context. Structures have a fixed set of fields that aren't interchangeable or dynamically computable, and since the tuple is a structure, not a collection, it follows the same rule. Its field names just look different.
It can be supported, it just needs to take a compile-time index. Since parameters of a function cannot be made constexpr, we need to wrap the index within a type and pass that instead. (e.g. std::integral_constant<std::size_t, N>.
The following is an extension of std::tuple that supports operator[].
template <typename... Ts>
class tuple : public std::tuple<Ts...> {
public:
using std::tuple<Ts...>::tuple;
template <std::size_t N>
decltype(auto) operator[](std::integral_constant<std::size_t, N>) {
return std::get<N>(*this);
}
};
It would be used like so:
tuple<int, std::string> x(42, "hello");
std::cout << x[std::integral_constant<std::size_t, 0>{}] << std::endl;
// prints: 42
To mitigate the std::integral_constant crazy, we can use variable template:
template <std::size_t N>
std::integral_constant<std::size_t, N> ic;
With this, we can say:
std::cout << x[ic<1>] << std::endl; // prints: hello
So it could be done. One guess as to why this is currently not available is because features such as std::integral_constant and variable templates may not have existed at the time std::tuple was introduced. As to why it doesn't exist even though those features exist, I would guess it's because no one have yet to proposed it.
It's not very clean supporting operator[] given you can't vary the static return type to match the accessed element. If the Standard Library had incorporated something like boost::any or boost::variant, it would make more sense.
Put another way, if you write something like:
int n = atoi(argv[1]);
int x = x[n];
Then what should it do if n doesn't address an int member of the tuple? To even support checking you'd need to store some manner of RunTime Type Information for tuples, which is extra overhead in the executable/memory.
Containers that support the subscript operator (i.e., operator[]) like std::vector or std::array are collections of homogenous values. Whatever the index provided to the subscript operator is, the value to return is always of the same type. Therefore, those containers can define a member function with the following declaration:
T& operator[](int);
Where T is the type of every element in the collection.
On the other hand, an std::tupe is a collection of heterogeneous values. The return value of a hypothetical subscript operator for std::tuple needs to vary with the index. Therefore, its return type depends on the index.
In the declaration of the operator[] given above, the index is provided as a function argument and therefore may be determined at run time. However, the return type of the function is something that needs to be determined at compile time, not at run time.
Since the return type of such a function depends on the index but must be determined at compile-time, the solution is to define instead a function template that accepts the index as a (non-type) template parameter. This way, the index is provided as a compile-time constant and the return type is able to change with the index:
template<std::size_t I, class... Types>
typename std::tuple_element<I, tuple<Types...>>::type& get(tuple<Types...>&) noexcept;
As you can see, std::get's return type depends on the index, I:
std::tuple_element<I, tuple<Types...>>::type&
Because tuple has no operator "bracket".
Why is it so? You cannot resolve templates based only on the return value. You cannot write
template<typename T>
T tuple::operator [](size_t i) const ;
Which is absolutely necessary to be able to allow statements like x[0]

Creating unordered_set of unordered_set

I want to create a container that will store unique sets of integers inside.
I want to create something similar to
std::unordered_set<std::unordered_set<unsigned int>>
But g++ does not let me do that and says:
invalid use of incomplete type 'struct std::hash<std::unordered_set<unsigned int> >'
What I want to achieve is to have unique sets of unsigned ints.
How can I do that?
I'm adding yet another answer to this question as currently no one has touched upon a key point.
Everyone is telling you that you need to create a hash function for unordered_set<unsigned>, and this is correct. You can do so by specializing std::hash<unordered_set<unsigned>>, or you can create your own functor and use it like this:
unordered_set<unordered_set<unsigned>, my_unordered_set_hash_functor> s;
Either way is fine. However there is a big problem you need to watch out for:
For any two unordered_set<unsigned> that compare equal (x == y), they must hash to the same value: hash(x) == hash(y). If you fail to follow this rule, you will get run time errors. Also note that the following two unordered_sets compare equal (using pseudo code here for clarity):
{1, 2, 3} == {3, 2, 1}
Therefore hash({1, 2, 3}) must equal hash({3, 2, 1}). Said differently, the unordered containers have an equality operator where order does not matter. So however you construct your hash function, its result must be independent of the order of the elements in the container.
Alternatively you can replace the equality predicate used in the unordered_set such that it does respect order:
unordered_set<unordered_set<unsigned>, my_unordered_set_hash_functor,
my_unordered_equal> s;
The burden of getting all of this right, makes:
unodered_set<set<unsigned>, my_set_hash_functor>
look fairly attractive. You still have to create a hash functor for set<unsigned>, but now you don't have to worry about getting the same hash code for {1, 2, 3} and {3, 2, 1}. Instead you have to make sure these hash codes are different.
I note that Walter's answer gives a hash functor that has the right behavior: it ignores order in computing the hash code. But then his answer (currently) tells you that this is not a good solution. :-) It actually is a good solution for unordered containers. An even better solution would be to return the sum of the individual hashes instead of hashing the sum of the elements.
You can do this, but like every unsorted_set/map element type the inner unsorted_set now needs a Hash function to be defined. It does not have one by default but you can write one yourself.
What you have to do is to define an appropriate hash for keys of type std::unordered_set<unsigned int> (since operator== is already defined for this key, you will not need to also provide the EqualKey template parameter for std::unordered_set<std::unordered_set<unsigned int>, Hash, EqualKey>.
One simple (albeit inefficient) option is to hash on the total sum of all elements of the set. This would look similar to this:
template<typename T>
struct hash_on_sum
: private std::hash<typename T::element_type>
{
typedef T::element_type count_type;
typedef std::hash<count_type> base;
std::size_t operator()(T const&obj) const
{
return base::operator()(std::accumulate(obj.begin(),obj.end(),count_type()));
}
};
typedef std::unordered_set<unsigned int> inner_type;
typedef std::unordered_set<inner_type, hash_on_sum<inner_type>> set_of_unique_sets;
However, while simple, this is not good, since it does not guarantee the following requirement. For two different parameters k1 and k2 that are not equal, the probability that std::hash<Key>()(k1) == std::hash<Key>()(k2) should be very small, approaching 1.0/std::numeric_limits<size_t>::max().
std::unordered_set<unsigned int>> does not meet the requirement to be an element of a std::unordered_set since there is no default hash function (i.e. std::hash<> is no specialized for std::unordered_set<unsigned int>> ).
you can provide one (it should be fast, and avoid collisions as much as possible) :
class MyHash
{
public:
std::size_t operator()(const std::unordered_set<unsigned int>& s) const
{
return ... // return some meaningful hash of the et elements
}
};
int main() {
std::unordered_set<std::unordered_set<unsigned int>, MyHash> u;
}
You can see very good examples of hash functions in this answer.
You should really provide both a Hash and an Equality function meeting the standard requirement of an Unordered Associative Container.
Hash() the default function to create hashes of your set's elements does not know how to deal with an entire set as an element. Create a hash function that creates a unique value for every unique set and you're good to go.
This is the constructor for an unordered_set
explicit unordered_set( size_type bucket_count = /*implementation-defined*/,
const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual(),
const Allocator& alloc = Allocator() );
http://en.cppreference.com/w/cpp/container/unordered_set/unordered_set
Perhaps the simplest thing for you to do is create a hash function for your unordered_set<unsigned int>
unsigned int my_hash(std::unordered_set<unsigned int>& element)
{
for( e : element )
{
some sort of math to create a unique hash for every unique set
}
}
edit: as seen in another answer, which I forgot completely, the hashing function must be within a Hash object. At least according to the constructor I pasted in my answer.
There's a reason there is no hash to unordered_set. An unordered_set is a mutable sequence by default. A hash must hold the same value for as long as the object is in the unordered_set. Thus your elements must be immutable. This is not guaranteed by using the modifier const&, as it only guaranties that only the main unordered_set and its methods will not modify the sub-unordered_set. Not using a reference could be a safe solution (you'd still have to write the hash function) but do you really want the overhead of moving/copying unordered_sets ?
You could instead use some kind of pointer. This is fine; a pointer is only a memory address and your unordered_set itself does not relocate (it might reallocate its element pool, but who cares ?). Therefore your pointer is constant and it can hold the same hash for its lifetime in the unordered_set.
( EDIT: as Howard pointed out, you must ensure that any order you element are stored for your set, if two sets have the same elements they are considered equal. By enforcing an order in how you store your integers, you freely get that two sets correspond to two equal vectors. )
As a bonus, you now can use a smart pointer within the main set itself to manage the memory of sub-unordered_set if you allocated them on the heap.
Note that this is still not your most efficient implementation to get a collection of sets of int. To make you sub-sets, you could write a quick wrapper around std::vector that stores the int, ordered by value. int int are small and cheap to compare, and using a dichotomic search is only O(log n) in complexity. A std::unordered_set is a heavy structure and what you lose by going from O(1) to O(log n), you gain it back by having compact memory for each sets. This shouldn't be too hard to implement but is almost guaranteed to be better in performance.
Harder to implements solution would involve a trie.

Why does std::vector transfer its constness to the contained objects?

A const int * and an int *const are very different. Similarly with const std::auto_ptr<int> vs. std::auto_ptr<const int>. However, there appears to be no such distinction with const std::vector<int> vs. std::vector<const int> (actually I'm not sure the second is even allowed). Why is this?
Sometimes I have a function which I want to pass a reference to a vector. The function shouldn't modify the vector itself (eg. no push_back()), but it wants to modify each of the contained values (say, increment them). Similarly, I might want a function to only change the vector structure but not modify any of its existing contents (though this would be odd). This kind of thing is possible with std::auto_ptr (for example), but because std::vector::front() (for example) is defined as
const T &front() const;
T &front();
rather than just
T &front() const;
There's no way to express this.
Examples of what I want to do:
//create a (non-modifiable) auto_ptr containing a (modifiable) int
const std::auto_ptr<int> a(new int(3));
//this works and makes sense - changing the value pointed to, not the pointer itself
*a = 4;
//this is an error, as it should be
a.reset();
//create a (non-modifiable) vector containing a (modifiable) int
const std::vector<int> v(1, 3);
//this makes sense to me but doesn't work - trying to change the value in the vector, not the vector itself
v.front() = 4;
//this is an error, as it should be
v.clear();
It's a design decision.
If you have a const container, it usually stands to reason that you don't want anybody to modify the elements that it contains, which are an intrinsic part of it. That the container completely "owns" these elements "solidifies the bond", if you will.
This is in contrast to the historic, more lower-level "container" implementations (i.e. raw arrays) which are more hands-off. As you quite rightly say, there is a big difference between int const* and int * const. But standard containers simply choose to pass the constness on.
The difference is that pointers to int do not own the ints that they point to, whereas a vector<int> does own the contained ints. A vector<int> can be conceptualised as a struct with int members, where the number of members just happens to be variable.
If you want to create a function that can modify the values contained in the vector but not the vector itself then you should design the function to accept iterator arguments.
Example:
void setAllToOne(std::vector<int>::iterator begin, std::vector<int>::iterator end)
{
std::for_each(begin, end, [](int& elem) { elem = 1; });
}
If you can afford to put the desired functionality in a header, then it can be made generic as:
template<typename OutputIterator>
void setAllToOne(OutputIterator begin, OutputIterator end)
{
typedef typename iterator_traits<OutputIterator>::reference ref;
std::for_each(begin, end, [](ref elem) { elem = 1; });
}
One big problem syntactically with what you suggest is this: a std::vector<const T> is not the same type as a std::vector<T>. Therefore, you could not pass a vector<T> to a function that expects a vector<const T> without some kind of conversion. Not a simple cast, but the creation of a new vector<const T>. And that new one could not simply share data with the old; it would have to either copy or move the data from the old one to the new one.
You can get away with this with std::shared_ptr, but that's because those are shared pointers. You can have two objects that reference the same pointer, so the conversion from a std::shared_ptr<T> to shared_ptr<const T> doesn't hurt (beyond bumping the reference count). There is no such thing as a shared_vector.
std::unique_ptr works too because they can only be moved from, not copied. Therefore, only one of them will ever have the pointer.
So what you're asking for is simply not possible.
You are correct, it is not possible to have a vector of const int primarily because the elements will not assignable (requirements for the type of the element contained in the vector).
If you want a function that only modifies the elements of a vector but not add elements to the vector itself, this is primarily what STL does for you -- have functions that are agnostic about which container a sequence of elements is contained in. The function simply takes a pair of iterators and does its thing for that sequence, completely oblivious to the fact that they are contained in a vector.
Look up "insert iterators" for getting to know about how to insert something into a container without needing to know what the elements are. E.g., back_inserter takes a container and all that it cares for is to know that the container has a member function called "push_back".

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

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:
#include <vector>
int main() {
std::vector <const int> v;
}
will not compile - you can't create a vector of const ints. Obviously, I should have known this (and intellectually I did), but I've never needed to create such a thing before. However, it seems like a useful construct to me, and I wonder if there is any way round this problem - I want to add things to a vector (or whatever), but they should not be changed once added.
There's probably some embarrassingly simple solution to this, but it's something I'd never considered before.
I probably should not have mentioned sorting (I may ask another question about that, see this for the difficulties of asking questions). My real base use case is something like this:
vector <const int> v; // ok (i.e. I want it to be OK)
v.push_back( 42 ); // ok
int n = v[0]; // ok
v[0] = 1; // not allowed
Well, in C++0x you can...
In C++03, there is a paragraph 23.1[lib.containers.requirements]/3, which says
The type of objects stored in these components must meet the requirements of CopyConstructible types (20.1.3), and the additional requirements of Assignable types.
This is what's currently preventing you from using const int as a type argument to std::vector.
However, in C++0x, this paragraph is missing, instead, T is required to be Destructible and additional requirements on T are specified per-expression, e.g. v = u on std::vector is only valid if T is MoveConstructible and MoveAssignable.
If I interpret those requirements correctly, it should be possible to instantiate std::vector<const int>, you'll just be missing some of its functionality (which I guess is what you wanted). You can fill it by passing a pair of iterators to the constructor. I think emplace_back() should work as well, though I failed to find explicit requirements on T for it.
You still won't be able to sort the vector in-place though.
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.
You can't create a vector of const ints, and it'd be pretty useless even if you could. If i remove the second int, then everything from there on is shifted down one -- read: modified -- making it impossible to guarantee that v[5] has the same value on two different occasions.
Add to that, a const can't be assigned to after it's declared, short of casting away the constness. And if you wanna do that, why are you using const in the first place?
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.
Although this doesn't meet all of your requirements (being able to sort), try a constant vector:
int values[] = {1, 3, 5, 2, 4, 6};
const std::vector<int> IDs(values, values + sizeof(values));
Although, you may want to use a std::list. With the list, the values don't need to change, only the links to them. Sorting is accomplished by changing the order of the links.
You may have to expend some brain power and write your own. :-(
I would have all my const objects in a standard array.
Then use a vector of pointers into the array.
A small utility class just to help you not have to de-reference the objects and hay presto.
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
class XPointer
{
public:
XPointer(int const& data)
: m_data(&data)
{}
operator int const&() const
{
return *m_data;
}
private:
int const* m_data;
};
int const data[] = { 15, 17, 22, 100, 3, 4};
std::vector<XPointer> sorted(data,data+6);
int main()
{
std::sort(sorted.begin(), sorted.end());
std::copy(sorted.begin(), sorted.end(), std::ostream_iterator<int>(std::cout, ", "));
int x = sorted[1];
}
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.
If constness is important to you in this instance I think you probably want to work with immutable types all the way up. Conceptually you'll have a fixed size, const array of const ints. Any time you need to change it (e.g. to add or remove elements, or to sort) you'll need to make a copy of the array with the operation performed and use that instead.
While this is very natural in a functional language it doesn't seem quite "right" in C++. getting efficient implementations of sort, for example, could be tricky - but you don't say what you're performance requirements are.
Whether you consider this route as being worth it from a performance/ custom code perspective or not I believe it is the correct approach.
After that holding the values by non-const pointer/ smart pointer is probably the best (but has its own overhead, of course).
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.
It is true that Assignable is one of the standard requirements for vector element type and const int is not assignable. However, I would expect that in a well-thought-through implementation the compilation should fail only if the code explicitly relies on assignment. For std::vector that would be insert and erase, for example.
In reality, in many implementations the compilation fails even if you are not using these methods. For example, Comeau fails to compile the plain std::vector<const int> a; because the corresponding specialization of std::allocator fails to compile. It reports no immediate problems with std::vector itself.
I believe it is a valid problem. The library-provided implementation std::allocator is supposed to fail if the type parameter is const-qualified. (I wonder if it is possible to make a custom implementation of std::allocator to force the whole thing to compile.) (It would also be interesting to know how VS manages to compile it) Again, with Comeau std::vector<const int> fails to compiler for the very same reasons std::allocator<const int> fails to compile, and, according to the specification of std::allocator it must fail to compile.
Of course, in any case any implementation has the right to fail to compile std::vector<const int> since it is allowed to fail by the language specification.
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;
You could derive a class const_vector from std::vector that overloads any method that returns a reference, and make it return a const reference instead. To do your sort, downcast back to std::vector.
std::vector of constant object will probably fail to compile due to Assignable requirement, as constant object can not be assigned. The same is true for Move Assignment also. This is also the problem I frequently face when working with a vector based map such as boost flat_map or Loki AssocVector. As it has internal implementation std::vector<std::pair<const Key,Value> > .
Thus it is almost impossible to follow const key requirement of map, which can be easily implemented for any node based map.
However it can be looked, whether std::vector<const T> means the vector should store a const T typed object, or it merely needs to return a non-mutable interface while accessing.
In that case, an implementation of std::vector<const T> is possible which follows Assignable/Move Assignable requirement as it stores object of type T rather than const T. The standard typedefs and allocator type need to be modified little to support standard requirements.Though to support such for a vector_map or flat_map, one probably needs considerable change in std::pair interface as it exposes the member variables first & second directly.
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).