Max
Max

Reputation: 1481

Check if vector is uninitialised at a certain position

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

Answers (4)

eerorika
eerorika

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

Fran&#231;ois Andrieux
Fran&#231;ois Andrieux

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 Atoms 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

P.W
P.W

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

JonAmazon
JonAmazon

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

Related Questions