Related
I'm new to C++. I'm a student coming from C.
My goal is to write a simple function that takes an array in parameter.
I succeed but i'm not happy with the result.
main.cpp
#include <array>
#include <iostream>
#include "MyMath.hpp"
int main()
{
std::array<int, 5> array = {1, 2, 3, 5, 4};
MyMath::sortIntArray(array);
std::cout << array.at(3) << std::endl;
return 0:
}
MyMath.hpp
#include <array>
class MyMath {
public:
static void sortIntArray(std::array<int, 5> &array)
{
array.at(3) = 99;
}
}
I created a class to contain my function because that's the school's coding style.
The problem that I have with the code above is that I wrote the size of my array in my function's parameter. "What if I want to sort an array of 500 numbers ?"
1)
So my question is : what is the best way to write the same function without having to write the array size ?
2)
I've done some research and I know about std::vector but isn't it more appropriate to use std::array when you want to create an array with fixed size ?
3)
I could solve my issue with C-Style array : by setting the last element of the array at NULL or by sending the size as an second parameter. But isn't more appropriate to use class equivalent for arrays and string ? (std::array / std::vector / std::string and almost never use int[] anymore)
4) I have seen "templates" that would allow me to success my goal but after writting the second little function of my sorting algorithm, I noticed that I would have to use template for every function that takes an std::array as parameter which is crazy.
If the answer is to simply use std::vector or int[]. Will I ever need std::array ? (because it is not better than int[] in my opinion, I could solve the problem with int[] as I said in 3). And I cannot solve the problem with std::array)
There are 4 questions. For my general undestanding of this langage, I think it is important to consider answering all 4 questions (even if it's only a very short sentence).
Thanks you in advance.
Look at the interface of std::sort. Instead of taking a concrete container type, it instead takes a generic [start, end) iterator pair. Then if the caller wants to sort a vector, they can pass in a pair of std::vector<int>::iterator_types. If they want to sort an array of 5 ints, they can pass in std::array<int, 5>::iterator_type. If they want to sort an C-style array, they can pass in int*s.
1) So my question is : what is the best way to write the same function without having to write the array size ?
There isn't a best way, it depends on what you need to do.
If you want to use std::array like that, you will have to use a template.
If you don't need the size at compile-time, you have more a few more options, e.g. the ones you describe later.
2) I've done some research and I know about std::vector but isn't it more appropriate to use std::array when you want to create an array with fixed size ?
Yes, it is. They aren't equivalent solutions and they are meant for different use cases.
3) I could solve my issue with C-Style array : by setting the last element of the array at NULL or by sending the size as an second parameter. But isn't more appropriate to use class equivalent for arrays and string ? (std::array / std::vector / std::string and almost never use int[] anymore)
It depends. Again, remember that using those solutions are not equivalent, because size won't be known at compile-time!
4) I have seen "templates" that would allow me to success my goal but after writting the second little function of my sorting algorithm, I noticed that I would have to use template for every function that takes an std::array as parameter which is crazy.
What do you mean by "crazy"?
std::array is typically the more C++ way of handling arrays whose sizes are fixed and known at compile time, rather than a C-style array. At least one benefit over the old array is ease of copying; a single assignment from one array to another, rather than an element-by-element copy, and helps combat accidental shallow copies.
If you don't know the size at compile time, use std::vector. You can use it's resize method once you know the actual size, and then treat it the same as you would an array or array (i.e., indexing with []).
I have a vector of Foo
vector<Foo> inputs
Foo is a struct with some score inside
struct Foo {
...
float score
bool winner
}
Now I want to sort inputs by score and only assign winner to the top 3. But I don't want to change the original inputs vector. So I guess I need to create a vector of reference then sort that? Is it legal to create a vector of reference? Is there an elegant way to do so?
Here two different way of creating a vector<Foo*>:
vector<Foo*> foor;
for (auto& x:inputs)
foor.push_back(&x);
vector<Foo*> foob(inputs.size(),nullptr);
transform(inputs.begin(), inputs.end(), foob.begin(), [](auto&x) {return &x;});
You can then use standard algorithms to sort your vectors of pointers without changing the original vector (if this is a requirement):
// decreasing order according to score
sort(foob.begin(), foob.end(), [](Foo*a, Foo*b)->bool {return a->score>b->score;});
You may finally change the top n elements, either using for_each_n() algorithm (if C++17) or simply with an ordinary loop.
Online demo
The only example code given was for pointers, and the IMO far more fitting std::reference_wrapper was only mentioned, with no indication of how it might be used in a situation like this. I want to fix that!
Non-owning pointers have at least 3 drawbacks:
the visual, from having to pepper &, *, and -> in code using them;
the practical: if all you want is a reference to one object, now you have a thing that can be subtracted from other pointers (which may not be related), be inc/decremented (if not const), do stuff in overload resolution or conversion, etc. – none of which you want. I'm sure everyone is laughing at this and saying 'I'd never make such silly mistakes', but you know in your gut that, on a long enough timeline, it will happen.
and the lack of self-documentation, as they have no innate semantics of ownership or lack thereof.
I typically prefer std::reference_wrapper, which
clearly self-documents its purely observational semantics,
can only yield a reference to an object, thus not having any pointer-like pitfalls, and
sidesteps many syntactical problems by implicitly converting to the real referred type, thus minimising operator noise where you can invoke conversion (pass to a function, initialise a reference, range-for, etc.)... albeit interfering with the modern preference for auto – at least until we get the proposed operator. or operator auto – and requiring the more verbose .get() in other cases or if you just want to avoid such inconsistencies. Still, I argue that these wrinkles are neither worse than those of pointers, nor likely to be permanent given various active proposals to prettify use of wrapper/proxy types.
I'd recommend that or another vocabulary class, especially for publicly exposed data. There are experimental proposal(s) for observer_ptrs and whatnot, but again, if you don't really want pointer-like behaviour, then you should be using a wrapper that models a reference... and we already have one of those.
So... the code in the accepted answer can be rewritten like so (now with #includes and my preferences for formatting):
#include <algorithm>
#include <functional>
#include <vector>
// ...
void
modify_top_n(std::vector<Foo>& v, int const n)
{
std::vector< std::reference_wrapper<Foo> > tmp{ v.begin(), v.end() };
std::nth_element( tmp.begin(), tmp.begin() + n, tmp.end(),
[](Foo const& f1, Foo const& f2){ return f1.score > f2.score; } );
std::for_each( tmp.begin(), tmp.begin() + n,
[](Foo& f){ f.winner = true; } );
}
This makes use of the range constructor to construct a range of reference_wrappers from the range of real Foos, and the implicit conversion to Foo& in the lambda argument lists to avoid having to do reference_wrapper.get() (and then we have the far less messy direct member access by . instead of ->).
Of course, this can be generalised: the main candidate for factoring out to a reusable helper function is the construction of a vector< reference_wrapper<Foo> > for arbitrary Foo, given only a pair of iterators-to-Foo. But we always have to leave something as an exercise to the reader. :P
If you really don't want to modify the original vector, then you'll have to sort a vector of pointers or indices into the original vector instead. To answer part of your question, no there's no way to make a vector of references and you shouldn't do so.
To find the top three (or n) elements, you don't even have to sort the whole vector. The STL's got you covered with std::nth_element (or std::partial_sort if you care about the order of the top elements), you would do something like this:
void modify_top_n(std::vector<Foo> &v, int n) {
std::vector<Foo*> tmp(v.size());
std::transform(v.begin(), v.end(), tmp.begin(), [](Foo &f) { return &f; });
std::nth_element(tmp.begin(), tmp.begin() + n, tmp.end(),
[](const Foo* f1, const Foo *f2) { return f1->score > f2->score; });
std::for_each(tmp.begin(), tmp.begin() + n, [](Foo *f) {
f->winner = true;
});
}
Assuming the vector has at least n entries. I used for_each just because it's easier when you have an iterator range, you can use a for loop as well (or for_each_n as Christophe mentioned, if you have C++17).
Answering the question on it's face value:
Vectors of references (as well as built-in arrays of them) are not legal in C++. Here is normative standard wording for arrays:
There shall be no references to references, no arrays of references,
and no pointers to references.
And for vectors it is forbidden by the fact that vector elements must be assignable (while references are not).
To have an array or vector of indirect objects, one can either use a non-owning pointer (std::vector<int*>), or, if a non-pointer access syntax is desired, a wrapper - std::reference_wrapper.
So I guess I need to create a vector of reference then sort that? Is it legal to create a vector of reference?
No, it is not possible to have a vector of references. There is std::reference_wrapper for such purpose, or you can use a bare pointer.
Besides the two ways shown by Christophe, one more way is a transform iterator adaptor, which can be used to sort the top 3 pointers / reference wrappers into an array using std::partial_sort_copy.
A transform iterator simply adapts an output iterator by calling a function to transform input upon assignment. There are no iterator adaptors in the standard library though, so you need to implement one yourself, or use a library.
Is there a C++ standard type for holding a vector having a constant size? For example, something like a tuple with all element types being the same, so I only have to provide the size as a template argument?
I would like to have the same/similar behavior as when using std::vector, but the type should be as compact and efficient as a raw array (so no dynamic allocation, no run-time size information, etc.)
I prefer a C++03-compatible solution, so reusing a std::tuple isn't what I want.
Does the following class do what I want?
template<typename T, int N>
struct vec
{
T component[N];
// (+ some logic and accessors like operator[]...)
};
// concrete example:
vec<int,3> myVector;
Does it really differ from just saying T myVector[N] (concrete example int myVector[3])? Because that's what I am currently doing but I'm experiencing a couple of problems, since raw arrays are "just pointers" (+ size information) and can't be used as return values as well as aren't really passed by value (no deep copy occures).
C++11 has std::array; which is basically the same as you wrote.
For C++03, use boost::array which is basically compatible to std::array.
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.
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).