0

I am trying to get int value from boost::variant. Code generate segmentation fault - why? I put comments in code which lines generate error. I supposed that

int numberInt = boost::get<int>(v);

will not working correctly so I changed it to

int *ptrInt = boost::get<int>(&v);

which is compiling but still I am not managed to get int value? Exactly the same is with double. String type is working.

#include <iostream>
#include "boost/variant.hpp"
#include <boost/variant/get.hpp>
using namespace std;

int main(int argc, char* argv[])
{
  boost::variant<int, double, std::string> v;
  v = 16;
  v = 3.1415;
  v = "hello new year";

  //int numberInt = boost::get<int>(v);     //1) not working
  //double numberDouble = boost::get<double>(v);//2) not working

  int *ptrInt = boost::get<int>(&v);        //3) compiling
  if(ptrInt) 
    cout << *ptrInt << endl;            //4) not displayed
  //cout << *ptrInt << endl;            //5) segmentation fault

  double *ptrDouble = boost::get<double>(&v);   //6) compiling
  if(ptrDouble) 
    cout << *ptrDouble << endl;         //7) not displayed
  //cout << *ptrDouble << endl;         //8) segmentation fault

  std::string caption = boost::get<string>(v);
  cout << caption << endl;          //9) working

  return 0;
}

// clear && clear && g++ test.cpp -std=c++11 -o test && ./test
user2856064
  • 541
  • 1
  • 8
  • 25

2 Answers2

2

I think you're misunderstanding what boost variant is. The documentation of the library describes the variant type as "multi-type, single value." (emphasis mine). Since you've assigned a value of type std::string, no other types of value is stored in the variant. A nice thing about variant (when compared to union) is described in the comments of the get function:

// Retrieves content of given variant object if content is of type T.
// Otherwise: pointer ver. returns 0; reference ver. throws bad_get.

So, if int numberInt = boost::get<int>(v); works correctly, it should throw an exception. And int *ptrInt = boost::get<int>(&v); should return a null pointer. Dereferencing a null pointer is undefined behaviour and likely the cause for your segmentation faults.

I think the behaviour that you're looking for is in tuple (found in both boost and std). A simple struct/class would work too if you don't mind giving a name for the member objects.

eerorika
  • 232,697
  • 12
  • 197
  • 326
2

I am afraid you did not understand how boost::variant worked. In type theory, a boost::variant is a Sum Type, or Algebraic Data Type.

This is also often called "discriminated union" and basically looks like (in this case):

struct Variant {
    size_t index;
    union {
        int a;
        double b;
        std::string c;
    } u;
};

Now, when you write v = 16 what happens is:

v.u.a = 16; v.index = 0;

When you then write v = 3.1415 what happens is:

v.u.b = 3.1415; v.index = 1;

And finally when you write v = "hello new year" what happens is:

v.u.c = "hello new year"; v.index = 2;

Note that, each time, the index representing which member of the union is currently active is updated... and therefore only a single member of the union is active at any point in time.

When you use boost::get<int>(&v) the code actually looks like:

int* get_0(Variant* v) {
    if (v && v->index == 0) { return &v->u.a; }
    return nullptr;
}

and therefore, since at this point v->index is 2, it returns a nullptr.

The only get that will work is boost::get<std::string>(&v) because it checks whether the index is 2, which it is, and therefore returns a pointer to v.u.c.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722