2015-01-03 2 views
0

Я пытаюсь получить значение int из boost :: variant. Код генерирует ошибку сегментации - почему? Я помещал комментарии в код, строки которых генерируют ошибку. Я полагал, чтоПолучить int from boost :: variant generate segmentation fault

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

не будет работать правильно, поэтому я изменил его

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

который компилирует, но до сих пор я не удалось получить значение INT? Точно так же и с двойным. Строковый тип работает.

#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 

ответ

2

Я думаю, вы не понимаете, какой вариант форсирования. Документация библиотеки описывает тип variant как «многотипное, одно значение». (акцент мой). Поскольку вы присвоили значение типа std::string, никакие другие типы значений не сохраняются в variant. Хорошая вещь о variant (по сравнению с union) описывается в комментариях функции get:

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

Так что, если int numberInt = boost::get<int>(v);работает правильно, он должен бросить исключение. И int *ptrInt = boost::get<int>(&v); должен вернуть нулевой указатель. Выделение нулевого указателя является неопределенным поведением и вероятностью причины сбоев сегментации.

Я думаю, что поведение, которое вы ищете, находится в tuple (найдено как в boost, так и в std). Простой struct/class будет работать, если вы не возражаете дать имя для объектов-членов.

2

Боюсь, вы не понимали, как работает boost::variant. В теории типов a boost::variant является типом суммы, или Algebraic Data Type.

Это также часто называют «предвзято союз» и в основном выглядит (в данном случае):

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

Теперь, когда вы пишете v = 16 что случается:

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

Когда ты тогда напишите v = 3.1415, что произойдет:

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

И, наконец, когда вы пишете v = "hello new year" что случается:

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

Обратите внимание, что каждый раз, то index, представляющий какой член union в настоящее время активно обновляется ... и поэтому только один член союза активен в любой момент времени.

При использовании boost::get<int>(&v) код на самом деле выглядит следующим образом:

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

и поэтому, так как в этот момент v->index является 2, она возвращает nullptr.

Единственный get, который будет работать в boost::get<std::string>(&v), поскольку он проверяет, является ли index является 2, что он есть, и поэтому возвращает указатель на v.u.c.

 Смежные вопросы

  • Нет связанных вопросов^_^