2

Assuming a struct containing a std::vector with items of type std::pair.

struct block {
    std::vector<std::pair<key_t, value_t>> items;
    block(const Data& d) : items()
    {
        items = std::vector<std::pair<key_t, value_t>>(d.size_);
    }
};

Later in the code, I assign a value to the vector at position 0:

block<key_t, value_t> b(*this);
std::pair<key_t, value_t> item = std::pair<key_t, value_t>(k, v);
b.items[0] = item;

Later in the code, I want to iterate over the vector and expect &bucket_item != NULL to be true only at position 0, because I only assigned a value at this position. In fact, &bucket_item != NULL is always true.

for (std::pair<key_t, value_t> item : b.items)
{
    if (&item != NULL)
    {
       ...
    }
}

I am not able to initialize the vector with NULL values like so:

items = std::vector<std::pair<key_t, value_t>>(d.size_, NULL);

How to solve this?

1
  • NULL is a pointer, so you would need to make the vector hold pointers to std::pairs and do the memory management by yourself. Commented May 16, 2015 at 19:40

5 Answers 5

3

It seems like you have Java background, C++ is a bit different.

items = std::vector<std::pair<key_t, value_t>>(d.size_);

items has already been initialized with its default constructor. The line above creates another default initialized container and assigns it to items, which is unnecessary.

In:

b.items[0] = item;

You need to make sure that the vector is big enough, because it does not allocate elements for you in operator[]. Either do b.items.push_front/back(item) or insert it at a specific position using vector::insert, e.g. b.items.insert(b.items.begin(), item). push_xxx and insert do allocate memory for new elements.

When you do

for (std::pair<key_t, value_t> item : b.items) 
{
    if (&item != NULL)

It iterates over all existing elements in the container. item is stored by value (unlike Java) in the container, so that it exists at a non-NULL address and cannot be possibly be equal to NULL.

However, expression for(std::pair<key_t, value_t> item : b.items) creates a copy of each element on the stack (also at non-NULL address), you probably want that to be for(std::pair<key_t, value_t>& item : b.items) to just refer to the element rather than copy it (note the ampersand symbol on the left of items). If you do not intend to modify item inside the loop, you may like to use const qualifier as well to make your intent clear to the reader of the code. e.g. for(std::pair<key_t, value_t> const& item : b.items).

And because you use C++11 anyway, you do not have to spell out the type of the container element, just use auto:

for (auto const& item : b.items) 
    // do something to item
Sign up to request clarification or add additional context in comments.

2 Comments

Also, the statement &item != NULL will always be true. Not just in this example, but in any valid C++-code.
Just being nitpicky here -- if the pair ins't being modified in the for each loop, I would even throw in the const just to be explicit about the intention of the loop
2

When you create an std::vector with a length len like this std::vector<T> tVec(len), you are creating a vector with len default-constructed objects of type T. If you want to represent a null value, you will need to resort to one of the following ways:

  1. Use a sentinel value of T to denote an invalid value.
  2. Use a (smart-)pointer to T and use a nullptr as the natural invalid value.
  3. Wrap a class around T which contains a bool marking it as invalid.

The last option is provided by boost::optional. Here's a rewrite of your code using it:

struct block {
    using OptionalPair_t = boost::optional<std::pair<key_t, value_t>>;
    std::vector<OptionalPair_t> items;
    block(const Data& d) : items(d.size_)
    {
    }
};

Since boost::optional is contextually convertible to bool, you can do this:

for (auto& item : b.items)
{
    if (item)
    {
       ...
    }
}

Comments

0

I think your mixing here a few definitions. an element of std::vector cannot be NULL, because it's not a pointer. and it defenilty exists. int arr[] = {1};, can arr[0] be null? of course not. why would it be ? it's a real integer who seat somwhere in the memory which is not null.

if you're iterating over a std::vector elements, that means they exist, so they can not be null.

Comments

0

NULL, or better nullptr, can be used to initialize a pointer value, but makes no sense to initialize, for example, an std::string or std::pair<std::string, int> with it.

If you want your vector to be empty, you can use:

std::vector<std::pair<key_t, value_t>> items;

othwerwise, if you want n default constructed std::pairs you can use:

std::vector<std::pair<key_t, value_t>> items(n);

Comments

0

Pair are really a comination of values. So you have to define which combination of values you consider as being the NULL equivalent for your pairs.

You can then initialize your vector with the following constructor:

std::vector<std::pair<key_t, value_t>> items(d.size_, make_pair(0,0)) ;

You just have to replace 0 with the neutral values for key_t and value_t.

Please note that vectors really contain values, and pairs are values. So there is no NULL pointers that would show absence of values.

2 Comments

What makes you think key_t(0) or value_t(0) is a valid expression?
@Jefffrey this is an illustration, to be adatapted with the neutral value applying to key_t and value_t. Of course, the 10 is also only an illustration for the desired size.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.