std::list of boost::arrays - c++
I ran into some trouble while using a list of arrays.
So to clear things up I do know that I can't have a std::list containing arrays.
I am using boost::array to be able to do that.
Currently I prototype all datatypes needed for my pathfinding algorithm and test them for speed and cache coherence.
typedef boost::array<int,2> VertexB2i;
typedef std::list<VertexB2i> VertexList;
These types are not used for pathfinding, they are simply easier to use then all the real c++ arrays and flags for the pathfinder, so they are just used to generate a navigation mesh.
(I also know I could use a stl::pair instead boost::array in this case, but I want to keep the generated data as similar to the pathfinders data as possible, so I don't have to deal with two totally different interfaces the whole time)
VertexList* vl = new VertexList();
vl->push_back({{8,28}}); // this does not work, why?
So while setting up some testing data for these two data-types, I noticed that the commented line does not work, although this does work:
VertexList* vl = new VertexList();
VertexB2i ver1 = {{8,28}};
vl->push_back({ver1}); // works
So to sum it up:
Is there anyway to pushback a "VertexB2i" without declaring it separte first?
General advices?
std::array (or boost::array) is an aggregate type. In C++98/03 it can only be initialized in the declarator:
std::array<int, 2> arr = { 1, 2 };
thelist.push_back(arr); // makes a copy
In C++11, you can use uniform initialization to create temporaries as well:
std::list<std::array<int,2>> l;
l.push_back(std::array<int,2>{{2,3}}); // maybe copy
l.emplace_back(std::array<int,2>{{2,3}}); // maybe copy, probably optimized out
Related
Conversion from std::vector<Eigen::Vector3d> to std::vector<Eigen::Vector3f>
I came across the problem that I want to convert from a std::vector<Eigen::Vector3d> to a std::vector<Eigen::Vector3f>. I was wondering if there is a solution where I dont have to iterate over the points. // mapping using iteration std::vector< Eigen::Vector3d> tf{ {1,1,1},{1,1,1},{1,1,1} }; std::vector< Eigen::Vector3f> tf2; tf2.reserve(tf.size()); std::transform(tf.begin(), tf.end(), std::back_inserter(tf2), [](const Eigen::Vector3d& p) { return p.cast<float>(); }); I tried some things like tf.data() and tried to cast that, but I didnt found a solution. I also looked into Eigen::Map<> class, but didnt really find a solution.
I don't think what you are asking is possible. Eigen::Map allows you to construct an Eigen data structure without needing to copy or move, it merely takes a view on existing contiguous data (typically from a std::array or std::vector). The operation you are looking to do, casting from doubles to float, two distinct types with different memory layouts, is an explicit operation. You would be shrinking the size of the vector in half. It is not possible to achieve this by taking a different view on the same data.
Assuming Vector3d and Vector3f don't introduce any padding (which is true for all compilers which Eigen supports), you could use an Eigen::Map<const Matrix3Xd> and .cast<float>() that into an Eigen::Map<Matrix3Xf> over the destination vector: std::vector< Eigen::Vector3d> tf{ {1,1,1},{1,1,1},{1,1,1} }; std::vector< Eigen::Vector3f> tf2(tf.size()); // target needs to be actually allocated Eigen::Matrix3Xf::Map(tf2[0].data(), 3, tf2.size()) = Eigen::Matrix3Xd::Map(tf[0].data(), 3, tf.size()).cast<float>(); With the upcoming 3.4 branch of Eigen you can also use iterators over the casted-map, like so: Eigen::Map<Eigen::Matrix3Xd> input(tf[0].data(), 3, tf.size()); std::vector<Eigen::Vector3f> tf2(input.cast<float>().colwise().begin(), input.cast<float>().colwise().end());
Dynamic initialization of 2 dimensional array of lists in C++
I need to init a 2-dim array of forward_list after I read its sizes from input. class Foo{ forward_list<int> * koo; int A, B; void boo(){ scanf("%d",&A); scanf("%d",&B); koo = new forward_list<int>[A][B]; koo[0][0] = 1; } }; Compiler: cannot convert ‘std::forward_list<int> (*)[1]’ to ‘std::forward_list<int>*’ in assignment adjList = new forward_list<int>[A][A]; CLion IDE: Subscribed value is not an array (at koo[0]) I don't do much C++ so I don't quite know what's wrong. How can I do this right? I need to access all forward_list in O(1), and would, therefore, prefer arrays or generally something fast. Btw: not sure if this is called dynamic initialization, let me know if I should change the title. Thanks.
A forward_list is incapable of reaching your performance requirement: "I need to access all forward_list in O(1)" you can see that in a comparision here: https://en.wikipedia.org/wiki/Linked_list#Linked_lists_vs._dynamic_arrays You can see that Indexing for a forward_list and other linked list variants is O(n). The simplest container type that does provide the O(1) indexing you're looking for is a vector or another of the dynamic array variants. I believe your current needs could be satisfied by doing something like: vector<vector<int>> koo(A, vector<int>(B)); It should be mentioned that while this will satisfy your performance requirements, a vector of vectors isn't a great solution; but you can look at it as a good stopgap solution.
Passing an array as a function argument in C++
If I have this function: void initPoints(sf::Vector2f points[]); Why can I do this: sf::Vector2f[] vecs = {sf::Vector2f(0,0), etc}; initPoints(vecs); But can't do this? initPoints({sf::Vector2f(0,0), etc}); VS gives me an error on the second one, but not on the first one.
By using std::vector or std::array you can resolve your problem easier :) Furthermore, std::vector is RAII-conform, so you don't have to manage the memory by yourself. Generally, STL classes are better than C-type arrays. #include <vector> #include <initializer_list> // ... std::vector<sf::Vector2f> vecs = { Vector2f(0,0), etc }; Then: initPoints(const std::vector<sf::Vector2f>& vec) { // ... } initPoints(vecs);
C++ generally doesn't allow you to pass an actual array as a function parameter. It has a convenience feature that makes you think that's possible, in that you can actually pass a pointer. In other words: void initPoints(sf::Vector2f points[]); Is the same thing as void initPoints(sf::Vector2f* points); Note that initPoints doesn't know the length of points, so generally you also pass a length parameter: void initPoints(sf:Vector2f* points, size_t length); What you're trying to do simply isn't valid pre-C++11. In C++11 you can overload initPoints() to take a std::initializer_list<sf::Vector2f>, and the syntax will work fine. The kind of array you're using is often called a "C-style array." It exists in C, and has existed in C++ from the beginning. It has various limitations, such as what you've just run into. It looks like you really want a std::vector. There is some nuance to using std::vectors, and I don't know your level of C++ understanding, so I don't know if the phrases "usually you don't want to pass them by value" or "I would recommend you imitate STL functions and pass begin/end iterators instead" mean anything to you. You will eventually come across the parts of the language that make those statements useful. You don't need to worry about them right now.
Initialize a Matrix of Pairs in Constructor
I'm creating a boardgame (Tzaar if curious :D) in openGL and I need to initialize my logical board with the starting pieces in each place. In my Game classe I have the following variable: std::pair<char,int> logicBoard[17][9]; and want to initialize it in the constructor following somewhat this example: logicBoard[][] = { {(0,0),(0,0),(0,0),(0,0),('z',1),(0,0),(0,0),(0,0),(0,0)}, {(0,0),(0,0),(0,0),('c',1),(0,0),('z',1),(0,0),(0,0),(0,0)}, {(0,0),(0,0),('c',1),(0,0),('y',1),(0,0),('z',1),(0,0),(0,0)}, {(0,0),('c',1),(0,0),('b',1),(0,0),('y',1),(0,0),('z',1),(0,0)}, {('c',1),(0,0),('b',1),(0,0),('x',1),(0,0),('y',1),(0,0),('c',1)}, {(0,0),('b',1),(0,0),('a',1),(0,0),('x',1),(0,0),('b',1),(0,0)}, {('z',1),(0,0),('a',1),(0,0),('z',1),(0,0),('a',1),(0,0),('c',1)}, {(0,0),('y',1),(0,0),('c',1),(0,0),('c',1),(0,0),('b',1),(0,0)}, {('z',1),(0,0),('x',1),(0,0),(0,0),(0,0),('a',1),(0,0),('c',1)}, {(0,0),('y',1),(0,0),('z',1),(0,0),('z',1),(0,0),('b',1),(0,0)}, {('z',1),(0,0),('x',1),(0,0),('c',1),(0,0),('x',1),(0,0),('c',1)}, {(0,0),('y',1),(0,0),('a',1),(0,0),('x',1),(0,0),('y',1),(0,0)}, {('z',1),(0,0),('b',1),(0,0),('a',1),(0,0),('y',1),(0,0),('z',1)}, {(0,0),('c',1),(0,0),('b',1),(0,0),('y',1),(0,0),('z',1),(0,0)}, {(0,0),(0,0),('c',1),(0,0),('b',1),(0,0),('z',1),(0,0),(0,0)}, {(0,0),(0,0),(0,0),('c',1),(0,0),('z',1),(0,0),(0,0),(0,0)}, {(0,0),(0,0),(0,0),(0,0),('c',1),(0,0),(0,0),(0,0),(0,0)} }; But since I'm not so in depth of C++, don't know the easiest way of doing so. Want it to be easily modified too since the board will be sent to Prolog (with the game logic) program through sockets, so it returns the modified board again to this variable.
Why not use a Container to better management of your pairs? It would be like this: std::vector< std::pair<char,int> > logicBoard; logicBoard.push_back({0, 1}); logicBoard.push_back({'c', 1}); And so on... This way if you ever need, lets say, the size of your "array" you can simply use logicBoard.size();
I would define a typedef, and here is a compilable snippet typedef std::pair<char,int> P; P logicBoard[17][9] = { {P(0,0),P(0,0),P(0,0),P(0,0),P('z',1),P(0,0),P(0,0),P(0,0),P(0,0)}, {P(0,0),P(0,0),P(0,0),P('c',1),P(0,0),P('z',1),P(0,0),P(0,0),P(0,0)}, {P(0,0),P(0,0),P('c',1),P(0,0),P('y',1),P(0,0),P('z',1),P(0,0),P(0,0)}, {P(0,0),P('c',1),P(0,0),P('b',1),P(0,0),P('y',1),P(0,0),P('z',1),P(0,0)}, {P('c',1),P(0,0),P('b',1),P(0,0),P('x',1),P(0,0),P('y',1),P(0,0),P('c',1)}, {P(0,0),P('b',1),P(0,0),P('a',1),P(0,0),P('x',1),P(0,0),P('b',1),P(0,0)}, {P('z',1),P(0,0),P('a',1),P(0,0),P('z',1),P(0,0),P('a',1),P(0,0),P('c',1)}, {P(0,0),P('y',1),P(0,0),P('c',1),P(0,0),P('c',1),P(0,0),P('b',1),P(0,0)}, {P('z',1),P(0,0),P('x',1),P(0,0),P(0,0),P(0,0),P('a',1),P(0,0),P('c',1)}, {P(0,0),P('y',1),P(0,0),P('z',1),P(0,0),P('z',1),P(0,0),P('b',1),P(0,0)}, {P('z',1),P(0,0),P('x',1),P(0,0),P('c',1),P(0,0),P('x',1),P(0,0),P('c',1)}, {P(0,0),P('y',1),P(0,0),P('a',1),P(0,0),P('x',1),P(0,0),P('y',1),P(0,0)}, {P('z',1),P(0,0),P('b',1),P(0,0),P('a',1),P(0,0),P('y',1),P(0,0),P('z',1)}, {P(0,0),P('c',1),P(0,0),P('b',1),P(0,0),P('y',1),P(0,0),P('z',1),P(0,0)}, {P(0,0),P(0,0),P('c',1),P(0,0),P('b',1),P(0,0),P('z',1),P(0,0),P(0,0)}, {P(0,0),P(0,0),P(0,0),P('c',1),P(0,0),P('z',1),P(0,0),P(0,0),P(0,0)}, {P(0,0),P(0,0),P(0,0),P(0,0),P('c',1),P(0,0),P(0,0),P(0,0),P(0,0)} }; BTW depending on your Prolog interface that should be adaptable to actually exchange values. In case, maybe you want to keep P lowercase.
Dynamic multi-dimensional array
I have to create a three-dimensional array using class A as element ,class A is defined like below, should I use vector<vector<vector<A> > > or boost::multi_array? Which one is better? struct C { int C_1; short C_2; }; class B { public: bool B_1; vector<C> C_; }; class A { public: bool A_1; B B_[6]; };
If you know the size of all three dimensions at the time, that you write your code, and if you don't need checking for array bounds, then just use traditional arrays: const int N1 = ... const int N2 = ... const int N3 = ... A a[N1][N2][N3] If the array dimensions can onlybe determined at run time, but remain constant after program initialization, and if array usage is distributed uniformly, then boost::multi_array is your friend. However, if a lot of dynamic extension is going on at runtime, and/or if array sizes are not uniform (for example, you need A[0][0][0...99] but only A[2][3][0...3]), then the nested vector is likely the best solution. In the case of non-uniform sizes, put the dimension, whose size variies the most, as last dimension. Also, in the nested vector solution, it is generally a good idea to put small dimensions first.
The main concern that I would have about using vector<vector<vector<A> > > would be making sure that the second- and third-level vectors all have the same length like they would in a traditional 3D array, since there would be nothing in the data type to enforce that. I'm not terribly familiar with boost::multi_array, but it looks like this isn't an issue there - you can resize() the whole array, but unless I'm mistaken you can't accidentally remove an item from the third row and leave it a different size than all of the other rows (for example). So assuming concerns like file size and compile time aren't much of an issue, I would think you'd want boost::multi_array. If those things are an issue, you might want to consider using a plain-old 3D array, since that should beat either of the other two options hands-down in those areas.