c++ map containing a list - c++

I would like to create a map where the key is an int, and the value is a list of arrays (int[][]).
I tried this :
const int R = 4, C = 5;
std::map<int, std::list<int[R][C]> > s;
but it won't compile and I don't understand why ... (R and C are parameter of the program but do not change during execution).

Arrays are not copy constructable or copy assignable, which an element of a standard container must be. Your code will compile as is, but the array type breaks the requirements for the standard containers and you'll run into undefined behaviour. You can't have an std::list<int[R][C]>. However, C++11 provides a nice new compile-time constant sized std::array for your pleasure:
typedef std::array<std::array<int, C>, R> array_2d;
typedef std::list<array_2d> array_list;
std::map<int, array_list> s;
Otherwise, other alternatives are to use std::vector instead of std::array (preferred), or to have a std::list of int** and dynamically allocate your 2D arrays.
However, I'd consider a bit of a rethink of your design. Is this really the structure you want? Should any of the data be grouped into a struct?

Related

Return std::array of unknown size

I would like to return a multidimensional std::array from my function. The size of the returned array shall be determined by the size of an input argument.
Something like:
std::array<std::array<unsigned int, n>, n> foo(std::vector<int> vec){
unsigned int n = vec.size;
std::array<std::array<unsigned int, n>, n> result;
return result;
}
It would be nice to solve this without an annoying additional template argument. std::vector instead of std::array seems not to be as straightforward to initialize with n (undetermined) items as std::array (without explicit initialization). How can this be made possible? Thank you!
First thing you need to know is that std::array has its size fixed at compile time, as the documentation from cppreference sais:
std::array is a container that encapsulates fixed size arrays.
This container is an aggregate type with the same semantics as a
struct holding a C-style array T[N] as its only non-static data
member.
If n comes from std::cin or from the command line arguments (or whatever kind of input out of compile time), then the compiler can't deduce the type, and therefore it will throw an error.
The most sensible way to do this is with std::vector, and you can do it like this:
std::vector<std::vector<unsigned int>> foo(std::vector<int> vec){
unsigned int n = vec.size();
std::vector<std::vector<unsigned int>> result(n, std::vector<unsigned int>(n));
return result;
}
Just initialize every vector using the size constructor of the vector.
You can create a n sized std::vector of n sized std::vector s using its c'tor, i.e:
std::vector<std::vector<unsigned int>> result(n, std::vector<unsigned int>(n, 0));
NOTE: According to cppreference.com, the second parameter used in the above example of std::vector s c'tor is for the value of each item to be created: c'tor signature:
vector( size_type count, const T& value, const Allocator& alloc = Allocator());.
Try using Boost.MultiArray. It allows you to create multidimensional arrays with contents of arbitrary content type. I have used it (the boost::multi_array_ref part to be more specific) and it works pretty nice. An important feature is the ability to create array views (and slices based on views).

Iterate all elements in std::vector using c-style API

According to “Item 16. Know how to pass vector and string data to legacy APIs.” of Effective STL of Scott Meyers:
It is safe to use c-style API to access all the elements of vector,
since vectors are guaranteed to have the same underlying memory layout as arrays.
//example 1, do sth to all elements in vector using c-style API
void doSomething(const int *pInts, size_t numlnts);
vector<int> v;
if (!v.empty()) {
doSomething(&v[0], v.size());
}
//example 2, init vector with c-style API
size_t fillArray(double *pArray, size_t arraySize);
vector<double> vd(maxNumDoubles);
vd.resize(fillArray(&vd[0], vd.size()));
To use vector together with c-style API, is there any requirement for the element type T in c++ standard?
Is it always safe if T is a build-in type or POD type?
No, there is no requirement for the element type T. The vector will allocate memory so that each element in the vector consumes sizeof(T) bytes. When you write a loop that iterates over the underlying array via pointer arithmetic (or indexing, which is pointer arithmetic under the hood), the exact same element size is used (sizeof(T)) during the increment/decrement.
However, assuming that you will be reading/writing the underlying data array in true C, then you will face limitation in the sense that C++ class types like std::string, MyCustomClass, etc. cannot be used as T because it will be impossible for your C functions to accept such types safely. As long as T is a type that both C++ and C languages know the storage size of (i.e. both can use sizeof(T) without compilation problems), then you will be in good shape.

Can I cast std::vector<int>* to int*? [duplicate]

This question already has answers here:
How to get std::vector pointer to the raw data?
(3 answers)
Closed 7 years ago.
Let's say I have a std::vector<int>* foo; and I have to use it as int* (array of int, not pointer to an int) for an old C type library PVM. As far as I am concerned this might work since the vector stores it's elements next to each other in memory just like arrays. So I tried (int*)foo, but somehow I get an error which I'm unable to debug, so I think this must be the problem. Any ideas, thoughts, elegant workarounds?
You can't cast the vector directly to an array because the vector object consists of pointers to the array data, not the array data itself, which is dynamically allocated. To access the underlying array, use the data() member function:
std::vector<int> vec;
int *arr = vec.data();
Or
std::vector<int> *vecp = new std::vector<int>;
int *arr = vecp->data();
Yes you can. You should prefer this answer by #ApproachingDarknessFish for using std::vector::data which was introduced in C++11.
However, if you are using an older version of C++ you can just use &foo[0] to get an int* to the start of the container.
See this question for why std::vector::data is preferred over &foo.front() and &foo[0] (both which will produce undefined behaviour if foo is empty!)
Have a look at this this answer regarding the contiguous layout of std::vector memory which references the standard:
23.2.6 Class template vector [vector]
1 A vector is a sequence container that supports random access iterators. In addition, it supports (amortized) constant time insert and erase operations at the end; insert and erase in the middle take linear time. Storage management is handled automatically, though hints can be given to improve efficiency. The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().

Constant-sized vector class?

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.

C++, with vector<int[2]> can I push_back({someNum1,someNum2})?

I have the vector:
vector<int[2]> storeInventory; //storeInventory[INDEX#]{ITEMNUM, QUANTITY}
and I am wanting to use the push_back() method to add new arrays to the inventory vector. Something similar to this:
const int ORANGE = 100001;
const int GRAPE = 100002
storeInventory.push_back({GRAPE,24});
storeInventory.push_back{ORANGE, 30};
However, when I try using the syntax as I have above I get the error Error: excpeted an expression. Is what I am trying just not possible, or am I just going about it the wrong way?
Built-in arrays are not Assignable or CopyConstructible. This violates container element requirements (at least for C++03 and earlier). In other words, you can't have std::vector of int[2] elements. You have to wrap your array type to satisfy the above requirements.
As it has already been suggested, std::array in a perfect candidate for a wrapper type in C++11. Or you can just do
struct Int2 {
int a[2];
};
and use std::vector<Int2>.
I don't believe it's possible to pass arrays like that. Consider using std::array instead:
vector<std::array<int, 2> > storeInventory;
storeInventory.push_back({{GRAPE,24}});
If it's only vector of int[2] you could use:
std::vector<std::pair<int, int>> vec
Adding elements:
int a, b;
vec.push_back(std::make_pair(a, b));
storeInventory.push_back({GRAPE, 24});
storeInventory.push_back({ORANGE, 30});
You can try this. I think you forgot parentheses.
C-style arrays are not copyable, so can't be used as the element type in a std::vector.
Simply use a std::vector<int *> :)