Reputation: 1481
This seems like a really basic thing to do, but anyway I couldn't manage to find a solution to it so far, because I always find only questions that are asking how to check if the vector is actually empty, which is not what I want to check for.
Consider this code example:
#include <iostream>
#include <vector>
using namespace std;
struct Atom {
int x,y;
int pol;
};
int main() {
vector<vector<Atom>> vec=vector<vector<Atom>>(5,vector<Atom>(5));
cout<<(vec[0][0]==nullptr); // this line doesn't compile, because the vector doesn't hold pointers.
return 0;
}
I'm trying to declare a vector of vectors of objects of a custom type. At the beginning of the Programm I will initialise the vector so that it has a specific size, but without assigning an actual object to it. Now I want to be able to check if I already assigned an object to a specific position of the vector. I would've liked to use something like vec==nullptr
but this doesn't work, because the objects in the vector aren't pointers. Unfortunately I can't just change the structs standard constructor to put some indicator value that I can check for like Atom.pol==-2
, because the class is created by ROS messages. Any other suggestions on how to check if I already assigned an object?
EDIT: pol will always be either -1 or 1 after I assigned an object. So is it safe to check Atom.pol==0
? When I tried to do this on ideone.com it always worked, but I assume that it's not guaranteed to be 0, right?!
Upvotes: 1
Views: 1398
Reputation: 238351
There is no way to check whether an object has been initialised. That said, elements of std::vector
are always initialised, so there is never a need to check either.
It seems that you want to represent an "unassigned" object. The standard library has a template for you: std::optional
. If you create a vector optional objects, those objects, when value-initialized, will be in "unassigned" state.
EDIT: pol will always be either -1 or 1 after I assigned an object. So is it safe to check Atom.pol==0?
Yes, that would be safe, since the constructor that you use initialises the elments using a value initialised argument.
If you can assume that some states of the object are "not valid", then you don't necessarily need to use std::optional
. If the value initialised state is such invalid state, then you don't need to add a default constructor to the class either. Just like a value initialised pointer compares equal to nullptr
, so too the integer members of the value initialised Atom
compare equal to 0.
but I assume that it's not guaranteed to be 0, right?!
It is guaranteed to be 0.
Upvotes: 4
Reputation: 29022
The solution to use pol == 0
should be fine, provided that pol == 0
is in fact not a normal state for that object to be in and that you don't try it with an uninitialized instance.
The std::vector
constructor you are using guaranties that the new elements are default inserted. If you are using the default allocator (which you are) then that performs value initialization of those new elements. Since Atom
is a class type with a default constructor that is neither user-provided nor deleted, then your instance of Atom
are zero initialized. That means each of Atom
's members' value is initialized to zero.
Beware that this is something std::vector
does. You need your Atom
s to be initialized to zero for this approach to work. If you tried the following, it would be undefined behavior. The Atom
members are not initialized, much less guaranteed to be zero :
int main()
{
Atom a;
std::cout << (a.pol == 0); // <- Not okay
}
You can force value initialization by adding {}
though :
int main()
{
Atom a{};
std::cout << (a.pol == 0); // <- Okay now
}
Edit : Accidentally used the same code sample for both examples.
Upvotes: 2
Reputation: 26800
If you want to initialize the members of Atom
to specific values and check if they are initialized, you can do this.
vector<vector<Atom>> vec=vector<vector<Atom>>(5,vector<Atom>(5, {1, 2, 3}));
This initializes x, y, pol
to 1, 2
and 3
respectively.
Minimal Example:
int main() {
using std::cout;
using std::vector;
vector<vector<Atom>> vec=vector<vector<Atom>>(5,vector<Atom>(5, {1, 2, 3}));
cout<<((vec[0][0]).x == 1) << "\n";
cout<<((vec[0][0]).y == 2) << "\n";
cout<<((vec[0][0]).pol == 3) << "\n";
cout<<((vec[0][0]).x == -1) << "\n";
cout<<((vec[0][0]).y == -1) << "\n";
cout<<((vec[0][0]).pol == -1) << "\n";
return 0;
}
See Demo
Upvotes: 1
Reputation: 92
One way to do this is to change the signature of vec
to,
vector<vector<Atom*>> vec=vector<vector<Atom*>>(5,vector<Atom*>(5));
Then you can do the null ptr check to see if a given element has been initialized. This does add some complexity though, as you have to handle the memory allocation yourself.
Upvotes: 1