I would like to represent a std::vector of a structure containing several integers as a "flatten" vector of integers, without copying the data.
I tried something with a reinterpret_cast as shown below:
#include <vector>
#include <iostream>
struct Tuple
{
int a, b, c;
};
int main()
{
// init
std::vector<Tuple> vec1(5);
for(size_t i=0; i<vec1.size(); ++i)
{
vec1[i].a = 3 * i + 0;
vec1[i].b = 3 * i + 1;
vec1[i].c = 3 * i + 2;
}
// flattening
std::vector<int>* vec2 = reinterpret_cast<std::vector<int>*>(&vec1);
// print
std::cout << "vec1 (" << vec1.size() << ") : ";
for(size_t i=0; i<vec1.size(); ++i)
{
std::cout << vec1.at(i).a << " " << vec1.at(i).b << " " << vec1.at(i).c << " ";
}
std::cout << std::endl;
std::cout << "vec2 (" << vec2->size() << ") : ";
for (size_t j = 0; j < vec2->size(); ++j)
{
std::cout << vec2->at(j) << " ";
}
std::cout << std::endl;
return 0;
}
which works well since the output is:
vec1 (5) : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
vec2 (15) : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
My questions are :
Is this behavior compiler dependent? (I am using g++ 6.3.0)
How vec2 knows that the size of the vector is 15 and not 5?
Is their any other solution avoiding the use of reinterpret_cast? (If I "accidentally" add a double member to Tuple, the resulting issue could be hard to track...)
If vec1 has a specific allocator: std::vector<Tuple,A<Tuple>>, what should be the type of vec2? std::vector<int> or std::vector<int,A<int>> or std::vector<int,A<Tuple>>?
You can't legally reinterpret_cast the entire vector to a different type of vector. But you can legally cast a pointer to struct to a pointer to the first element of that struct. So this works:
std::vector<Tuple> vec1(5);
int* vec2 = &vec1.front().a;
size_t vec2_size = vec1.size() * sizeof(vec1[0]) / sizeof(vec2[0]);
for (size_t j = 0; j < vec2_size; ++j)
{
std::cout << vec2[j] << " ";
}
You need to make sure there's no padding in Tuple, so:
static_assert(sizeof(Tuple) == 3 * sizeof(int), "Tuple must be 3 ints");
To answer your bulleted questions:
Is this behavior compiler dependent?
Your code was illegal.
How vec2 knows that the size of the vector is 15 and not 5?
You got lucky, your code was illegal.
Is their any other solution avoiding the use of reinterpret_cast?
See above.
If vec1 has a specific allocator: std::vector>, what should be the type of vec2?
Same as above, int*.
Related
I have just started using range based for loops to simplify my code when using templates. I have come across a strange error and am not sure if this is something that I am missing or if the compiler is making a mistake. I have written a piece of code to illustrate the issue that I am having as well as the output. These are shown below.
Note: I am using the Mingw64 compiler on windows g++ (rev5, Built by MinGW-W64 project) 4.8.1 compiled without optimization with the --std=c++11 flag.
Code:
#include <iostream>
#include <array>
#include <vector>
int main()
{
// Declares an array of size 5 and of type int and intialises.
std::array<int,5> x = {1,2,3,4,5};
std::vector<int> y = {1,2,3,4,5};
// Prints each element
std::cout << "Array:" << std::endl;
std::cout << "x" << "\t" << "i" << std::endl;
for (auto i : x)
{
std::cout << x[i] << "\t" << i << std::endl;
}
std::cout << "Vector" << std::endl;
std::cout << "y" << "\t" << "i" << std::endl;
for (auto i : y)
{
std::cout << y[i] << "\t" << i << std::endl;
}
std::cin.get();
std::cin.get();
return 0;
}
Output:
Array:
x i
2 1
3 2
4 3
5 4
0 5
Vector
y i
2 1
3 2
4 3
5 4
1313429340 5
I would assume that the last line of both the vector and array output is an overflow, and notice how i starts at one instead of zero?? I would have assumed it would behave as described here.
I think you have not understood the syntax correctly
for (auto i : x)
here i is not an index of an array, it is the actual element inside the vector x.
So it is doing its job correctly.
"i" is the actual value in the array and not the index. So it is printing x[1] to x[5] in the first column and 1 to 5 in the second column. To access the values just print "i".
for (auto i : x)
creates copies of elements in x to be used inside your for loop. Use an iterator instead to access elements by their index.
for (size_t i = 0; i < x.size(); i++) {
std::cout << x[i] << "\t" << i << std::endl;
}
I think Eigen uses compressed methods to store sparse matrices. Is there any way that I can extract Triplet-format vectors of an Eigen sparse matrix in from of std::vectors?
Thanks.
More info (an example of triplet format)
Triplet format of matrix :
A=
3 0 4 0
0 0 1 0
0 2 0 5
4 0 0 0
i = 1 1 2 3 3 4 // row
j = 1 3 3 2 4 1 // column
S = 3 4 1 2 5 4 // values
The answer to the question, which is:
// Is there some method such as:
std::vector<Eigen::Triplet<double>> T = SparseMat.to_triplets();
// in Eigen?
Is no, there does not appear to be such a function.
Instead,
std::vector<Eigen::Triplet<double>> to_triplets(Eigen::SparseMatrix<double> & M){
std::vector<Eigen::Triplet<double>> v;
for(int i = 0; i < M.outerSize(); i++)
for(typename Eigen::SparseMatrix<double>::InnerIterator it(M,i); it; ++it)
v.emplace_back(it.row(),it.col(),it.value());
return v;
}
auto t = to_triplets(SparseMat);
And if you want to do it faster, open it in an IDE, look around for pointers to the data arrays, and write a convoluted function that will have no effect on runtime, since the matrix is sparse, and copying is linear in terms of nonzero elements.
Simply as shown in the tutorial:
#include <Eigen/Sparse>
#include <iostream>
using namespace Eigen;
using std::cout;
using std::endl;
typedef Triplet<int> Trip;
int main(int argc, char *argv[]){
std::vector<Trip> trp, tmp;
// I subtracted 1 from the indices so that the output matches your question
trp.push_back(Trip(1-1,1-1,3));
trp.push_back(Trip(1-1,3-1,4));
trp.push_back(Trip(2-1,3-1,1));
trp.push_back(Trip(3-1,2-1,2));
trp.push_back(Trip(3-1,4-1,5));
trp.push_back(Trip(4-1,1-1,4));
int rows, cols;
rows = cols = 4;
SparseMatrix<int> A(rows,cols);
A.setFromTriplets(trp.begin(), trp.end());
cout << "Matrix from triplets:" << endl;
cout << A << endl;
cout << endl << "Triplets:" << endl;
cout << "Row\tCol\tVal" <<endl;
for (int k=0; k < A.outerSize(); ++k)
{
for (SparseMatrix<int>::InnerIterator it(A,k); it; ++it)
{
cout << 1+it.row() << "\t"; // row index
cout << 1+it.col() << "\t"; // col index (here it is equal to k)
cout << it.value() << endl;
}
}
return 0;
}
I'm trying to read pairs values from a file in the constructor of an object.
The file looks like this:
4
1 1
2 2
3 3
4 4
The first number is number of pairs to read.
In some of the lines the values seem to have been correctly written into the vector. In the next they are gone. I am totally confused
inline
BaseInterpolator::BaseInterpolator(std::string data_file_name)
{
std::ifstream in_file(data_file_name);
if (!in_file) {
std::cerr << "Can't open input file " << data_file_name << std::endl;
exit(EXIT_FAILURE);
}
size_t n;
in_file >> n;
xs_.reserve(n);
ys_.reserve(n);
size_t i = 0;
while(in_file >> xs_[i] >> ys_[i])
{
// this line prints correct values i.e. 1 1, 2 2, 3 3, 4 4
std::cout << xs_[i] << " " << ys_[i] << std::endl;
// this lines prints xs_.size() = 0
std::cout << "xs_.size() = " << xs_.size() << std::endl;
if(i + 1 < n)
i += 1;
else
break;
// this line prints 0 0, 0 0, 0 0
std::cout << xs_[i] << " " << ys_[i] << std::endl;
}
// this line prints correct values i.e. 4 4
std::cout << xs_[i] << " " << ys_[i] << std::endl;
// this lines prints xs_.size() = 0
std::cout << "xs_.size() = " << xs_.size() << std::endl;
}
The class is defined thus:
class BaseInterpolator
{
public:
~BaseInterpolator();
BaseInterpolator();
BaseInterpolator(std::vector<double> &xs, std::vector<double> &ys);
BaseInterpolator(std::string data_file_name);
virtual int interpolate(std::vector<double> &x, std::vector<double> &fx) = 0;
virtual int interpolate(std::string input_file_name,
std::string output_file_name) = 0;
protected:
std::vector<double> xs_;
std::vector<double> ys_;
};
You're experiencing undefined behaviour. It seems like it's half working, but that's twice as bad as not working at all.
The problem is this:
xs_.reserve(n);
ys_.reserve(n);
You are only reserving a size, not creating it.
Replace it by :
xs_.resize(n);
ys_.resize(n);
Now, xs[i] with i < n is actually valid.
If in doubt, use xs_.at(i) instead of xs_[i]. It performs an additional boundary check which saves you the trouble from debugging without knowing where to start.
You're using reserve(), which increases capacity (storage space), but does not increase the size of the vector (i.e. it does not add any objects into it). You should use resize() instead. This will take care of size() being 0.
You're printing the xs_[i] and ys_[i] after you increment i. It's natural those will be 0 (or perhaps a random value) - you haven't initialised them yet.
vector::reserve reserve space for further operation but don't change the size of the vector, you should use vector::resize.
Please look at the small test code + output provided below. It seems that when using push_back() on an std::vector within a loop, C++ allocates the memory at 'random' addresses, and then re-copies the data into consecutive memory addresses after the loop is finished.
Is this to do with the fact that the size of the vector is not known before the loop?
What is the correct way of doing what I do in the test code? Do I have to assign the pointers in another loop after the first one exits? Note that I cannot define the size of the vector before the first loop, because in reality it is actually a vector of class objects that require initialization.
Thank you for your help.
std::vector<int> MyVec;
std::vector<int *> MyVecPtr;
for (int i = 0; i < 10; i++)
{
MyVec.push_back(i);
MyVecPtr.push_back(&MyVec.back());
std::cout << MyVec.back() << " "
<< &MyVec.back() << " "
<< MyVecPtr.back() << " "
<< *MyVecPtr.back() << std::endl;
}
std::cout << std::endl;
for (int i = 0; i < MyVec.size(); i++)
{
std::cout << MyVec[i] << " "
<< &MyVec[i] << " "
<< MyVecPtr[i] << " "
<< *MyVecPtr[i] << std::endl;
}
0 0x180d010 0x180d010 0
1 0x180d054 0x180d054 1
2 0x180d038 0x180d038 2
3 0x180d03c 0x180d03c 3
4 0x180d0b0 0x180d0b0 4
5 0x180d0b4 0x180d0b4 5
6 0x180d0b8 0x180d0b8 6
7 0x180d0bc 0x180d0bc 7
8 0x180d140 0x180d140 8
9 0x180d144 0x180d144 9
0 0x180d120 0x180d010 25219136
1 0x180d124 0x180d054 0
2 0x180d128 0x180d038 2
3 0x180d12c 0x180d03c 3
4 0x180d130 0x180d0b0 4
5 0x180d134 0x180d0b4 5
6 0x180d138 0x180d0b8 6
7 0x180d13c 0x180d0bc 7
8 0x180d140 0x180d140 8
9 0x180d144 0x180d144 9
If you know how many insertions you will be performing, you should use reserve() on your vector accordingly. This will eliminate the need for any resizing it would otherwise perform when the capacity is exceeded.
MyVec.reserve(10);
for (int i = 0; i < 10; i++)
{
MyVec.push_back(i);
//...
I am trying to construct a device which will do one thing for a value (specifically, a native type) and another thing for a C-style array of primitives.
This is what I have now, which does not do what I wish.
#include <cstdlib>
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;
template<class V> void dump_buf(const V& val)
{
cout << "val = " << val << "\n";
}
template<class A> void dump_buf(const A ary[])
{
cout << "ary size = " << sizeof(ary) << "\n";
for( size_t i = 0; i < sizeof(ary); ++i )
cout << "\t" << i+1 << " : " << ary[i] << "\n";
}
int main()
{
cout << "\n";
int i = 42;
float f = 3.14f;
unsigned fib[] = {0,1,1,2,3,5};
char s[] = "hello";
dump_buf(i);
dump_buf(f);
dump_buf(s);
dump_buf(fib);
}
This doesn't work because ary is of type pointer-to-something, not array-of-something. The output for the above (Intel, x64 compile, VS9) is:
val = 42
val = 3.14
ary size = 8
1 : h
2 : e
3 : l
4 : l
5 : o
6 :
7 : ╠
8 : ╠
ary size = 8
1 : 0
2 : 1
3 : 1
4 : 2
5 : 3
6 : 5
7 : 3435973836
8 : 3435973836
But I want the output to be:
val = 42
val = 3.14
ary size = 6
1 : h
2 : e
3 : l
4 : l
5 : o
6 :
ary size = 6
1 : 0
2 : 1
3 : 1
4 : 2
5 : 3
6 : 5
Note that the desired output for the string is 6 characters rather than 5 because of the null-terminator, which is part of the array.
Is there any way to get this to work, using only Standard C++ and no additional libraries?
Nearly any Standard-conformant technique would be acceptable. Overloading, template specialization, overriding, class templates... all are OK. I'm wide open to almost any technique that will accomplish my goal.
This should do the trick:
template<class A, size_t S> void dump_buf(const A (& ary)[S])
{
cout << "ary size = " << S << "\n";
for( size_t i = 0; i < S; ++i )
cout << "\t" << i+1 << " : " << ary[i] << "\n";
}
By taking a reference to an array, rather than a pointer to the start of an array, the size is known and available as an inferred template argument.
Also, remember that sizeof gives the size in bytes, so when you do want the number of objects in an array (and can't or don't want to use a template like this), you want sizeof(ary)/sizeof(*ary). In both cases, you need a real array, not a pointer to an array, which has lost all knowledge of the array's size.