C++,ANTLR and VECTORS - c++

I have an ANTLR rule that would return a vector:
main returns [std::vector<int> v]
:
('ERROR' t3=INT{v.push_back(atoi((const char*)$t3.text->chars));}
'='t4=INT{v.push_back(atoi((const char*)$t4.text->chars));}
);
Then I call it from C++ and try to get the vector data.
However, my problem is that ANTLR3 automatically initialized the vector v to NULL, which isn't allowed and gives me an error.
If I generate the C++ output of antlr and try to compile with my project it gives an error.
I manually went to the parsedfile that ANTLR outputs and removed the setting to NULL option and compiled again and everything worked out.
I can possibly see to solutions to this problem:
1) initializing the vector myself from ANTLR (DONT KNOW HOW TO INITIALIZE VECTORS)
2) Prevent ANTLR from initializing my vector (Not sure if it can be done)
3) Always manually go change the initialization (Not good practice)
4) Find another way to return the vector, tried to return a pointer to array I get the following error:
error: conversion from ‘std::vector<int, std::allocator<int> >*’ to non-scalar type ‘std::vector<int, std::allocator<int> >’ requested
Any help?

I think you want to do something like this:
main returns [std::vector<int> *v]
:
#init { v = new std::vector<int>(); }
( rule content, using *v in actions );
ANTLR can then initialize your return value to NULL, which I think it always does. The #init block creates an empty vector for you to use.
Of course, you will want to actually use a smart pointer like shared_ptr to avoid potential memory leaks as well.

You can initialize vectors this way:
vector<int> a(2,3); //vector a contains 2 elements: 3 and 3
a[0] = 4;//vector a contains 2 elements: 4 and 3
vector<int> b;
b = a;
And there are some other ways you can check here: http://www.cplusplus.com/reference/vector/vector/vector/
EDIT:
If you want to initialize with zeros:
vector<int> a(2);
should do the work, the vector a will contain 2 zeros.

Related

Assigning elements to Eigen::Vector2d within std vector throws error

I went through few StackOverflow posts but didn't find such error. I am trying to write a simple class which does a few operations on Eigen vectors and matrices. I created a class called MyClass and it has a method by the name MyMethod. It's code is as follows
void MyClass::MyMethod(Eigen::Vector4f X,
std::vector<Eigen::Vector2i> &pixelIndices,
std::vector<Eigen::Vector4f> vertices)
{
// Do some preprocessing
//Deleacring the std vector
std::vector<Eigen::Vector2i> currTriangle(3);
currTriangle[0] = Eigen::Vector2i(0); //Error occurs here
// Do some more processing
}
Upon executing method from a main function error occurs at the said statement. The error output is given below.
$: ./test1
test1: /usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h:285: void Eigen::PlainObjectBase<Derived>::resize(Eigen::Index) [with Derived = Eigen::Matrix<int, 2, 1>; Eigen::Index = long int]: Assertion `((SizeAtCompileTime == Dynamic && (MaxSizeAtCompileTime==Dynamic || size<=MaxSizeAtCompileTime)) || SizeAtCompileTime == size) && size>=0' failed.
Aborted (core dumped)
I know that using STL containers with Eigen is problematic, but as mentioned in the documentation the problems seems to be only with fixed size vectorizable Eigen types (that is they should be of 16 byte size), but Vector2i is not such a Eigen type. The assert statement is called in resize() method of PlainObjectBase, which is also weird because I haven't used it anywhere in the code.
Has anyone else faced this error? Any help will be really appreciated.
Update:
The error seems to be not because I used std::vector. I made this small changes to the code.
void MyClass::MyMethod(Eigen::Vector4f X,
std::vector<Eigen::Vector2i> &pixelIndices,
std::vector<Eigen::Vector4f> vertices)
{
// Do some preprocessing
Eigen::Vector2i temp(0); //Same Error occures here also
//Deleacring the std vector
std::vector<Eigen::Vector2i> currTriangle(3);
currTriangle[0] = Eigen::Vector2i(0);
// Do some more processing
}
So it seems like the error occurs when initializing the Vector2i.
As #MarcGlisse pointed out, Vector2i(0) tells to construct a Vector2i with 0 elements, which will fail at runtime. The reason why fixed sized matrices/vectors constructed with a single scalar interpret this as size rather than value is to allow generic functions, where it is not clear whether the size dynamic or fixed:
template<int SizeAtCompileTime>
void foo(){
Eigen::Matrix<int, SizeAtCompileTime, 1> v(actualSize);
// ...
}
There are two border-cases: Passing two integers to a vector with two elements or passing one integer to a vector with one element, will cause the vector to be initialized with that value(s) if the scalar type of the vector can implicitly constructed from the passed integer type -- otherwise, it will be interpreted as size.
To solve your original problem, there are several alternatives:
Eigen::Vector2i temp1(Eigen::Vector2i::Zero());
Eigen::Vector2i temp2(0,0);
// initialize all elements with a Zero vector:
std::vector<Eigen::Vector2i> currTriangle(3, Eigen::Vector2i::Zero());
currTriangle[0].setZero(); // set 0th element to Zero vector
currTriangle[0].setConstant(0); // equivalent to setZero, but works for arbitrary constants
currTriangle[0].array() = 0; // .array() lets you do element-wise operations

Arrow operator and vectors

I've been attempting to reassign a particular vector element to a new value and received a error from the compiler, and I'm not sure I understand it. So I believed that you could reassign a single vector element in the same way you could reassign an array's element.
std::vector<int> myVector[10];
myVector[5] = 6;
Or you could alternatively use the built in '.at' to access the vector with bounds checking. When I was writing some trivial code just to understand some concepts better I ran across a peculiar situation.
int main()
{
std::vector<int> test[10];
test[3] = 5;
if (test[3] != 6)
{
std::cout << "It works!" << std::endl;
}
return 0;
}
Now this piece of code flags an error saying that the assignment operator '=' and the logical operator '!=' doesn't match based on these operands. Now if I use the arrow operator '->' the code works just fine. Which is good, but I thought, perhaps mistakenly, that the arrow operator was used when dereferencing a pointer-to-object. I attempted to google these results, but perhaps due to the very rudimentary nature of it, I couldn't find much on the topic. Although, I would like to mention on a few sites with "c++ tutorials" I did see that they used the assignment operator without dereferencing the vector. Now this happens in both Visual Studios 2017 as well as the most recent version of Code::Blocks. Was I wrong? Do you actually need to utilize the arrow operator? Or am I missing something even more basic?
You created an array of 10 vectors, not a vector of 10 elements. A vector is is ultimately a class type, so you need to initialize it via a constructor:
std::vector<int> test(10);
The way you did it originally, meant you tried to assign the value 5 for the vector at index 3. Vectors don't support being assigned numbers, so that's what the error is about.
You're declaring an array of vectors rather than one vector of some initial length. Use the following instead of your declaration:
std::vector<int> myVector(10);

For each in c++ and assigning values to std::vector

How can I assign values to elements of std::vector using "for each" instruction?
I tried to do something like this:
std::vector<int> A(5);
for each(auto& a in A)
a = 4;
But then I get the following error:
error C3892 : 'a' : you cannot assign to a variable that is const
The for_each algorithm does not seem appropriate for that type of problem. Let me know if I am misunderstanding the issue.
// You can set each value to the same during construction
std::vector<int> A(10, 4); // 10 elements all equal to 4
// post construction, you can use std::fill
std::fill(A.begin(), A.end(), 4);
// or if you need different values via a predicate function or functor
std::generate(A.begin(), A.end(), predicate);
// if you really want to loop, you can do that too if your compiler
// supports it VS2010 does not yet support this way but the above
// options have been part of the STL for many years.
for (int &i : A) i = 4;
Personally, I have not ever found a good use for the for_each algorithm. It must be good for something because it was put into the library but I have never needed it in over 10 years of C++ programming. That one isn't particularly useful in my opinion.

C++ using std::accumulate to generate a map<int,int>

I have a problem creating a std::map<int, int> from a vector of pointers, called files. Each pointer points to an object with three member variables, one of which is size of type int. The key of the map would be the size and the value would be the number of objects which have the same size.
Do NOT waste your time on the second one! It is the next step in my program and I have figured it out already, I think. For initialization of the map I am using std::accumulate, because it returns a value. I am using std::tr1::shared_ptr for the pointers and a lambda expression for the predicate function. I am having problems with compilation.
Here's the code snippet:
map<int,int>* sizes = new map<int,int>();
sizes = accumulate(files.begin(), files.end(),sizes,
[&sizes](map<int,int> acc, shared_ptr<CFileType>& obj)
{
return sizes->insert(pair<int,int>(obj->getSize(),0));
});
Here's the error:
error C2664: 'std::pair<_Ty1,_Ty2> `anonymous-namespace'::::operator ()(std::map<_Kty,_Ty>,std::tr1::shared_ptr &) const' : cannot convert parameter 1 from 'std::map<_Kty,_Ty> ' to 'std::map<_Kty,_Ty>'
I am not very sure what to pass to the lambda function. I have tried with pair<int, int>, but it didn't work. Also, I must mention that this map is returned to another function, so it has to be a pointer.
Any help from you would be appreciated. Thanks!
UPDATE:
Problem solved, here is the solution:
map<int,int>* sizes = accumulate(files.begin(), files.end(), new map<int,int>(),
[](map<int,int>* acc, shared_ptr<CFileType>& obj)->map<int,int>*
{
acc->insert(pair<int,int>(obj->getSize(),0));
return acc;
});
The error message is that you have a type mismatch between the two kinds of std::maps. It looks like the error is in the code that calls the lambda, which apparently passes the wrong thing for the acc parameter. The good news is that the lambda, as posted, never actually uses the acc parameter.

std::list of boost::arrays

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