7

I want to access shared ptr, which is in union, though segmentation fault happens:

struct union_tmp
{
    union_tmp()
    {}
    ~union_tmp()
    {}
    union
    {
        int a;
        std::shared_ptr<std::vector<int>> ptr;
    };
};

int main()
{
    union_tmp b;
    std::shared_ptr<std::vector<int>> tmp(new std::vector<int>);
    b.ptr = tmp; //here segmentation fault happens
    return 0;
}

What is the reason of an error and how can I avoid it?

Aleksandr Tukallo
  • 1,299
  • 17
  • 22
  • That code does not produce a segfault – Rerito Oct 28 '16 at 09:30
  • 2
    @Rerito: That code exhibits undefined behaviour. *Anything* can happen. – Martin Bonner supports Monica Oct 28 '16 at 09:32
  • 3
    What are your actually trying to achieve here? A union of an int ansd a shared_ptr is a rather strange beast. This feels like it may be an [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) – Martin Bonner supports Monica Oct 28 '16 at 09:33
  • 2
    @MartinBonner I encountered the problem, when I was writing a _small_ _number_ _optimization_ for my big integer class for long arithmetics. My big integer class contains a vector, which stores big number by base 2^32. The idea is not to store a vector, but to store such union, so the memory will not be allocated if the value of big integer is less, than 2^32. I use shared pointer, not usual one, to add also _copy-on-write optimization_ later. – Aleksandr Tukallo Oct 28 '16 at 09:41
  • 1
    OK. That's an entirely reasonable usage :-) (Although personally, I would want to use `uintmax_t` rather than `int` - but it doesn't change the example). Presumably you currently have a flag elsewhere to indicate what the union holds. I would use `std::variant`, and let it hold the flag. – Martin Bonner supports Monica Oct 28 '16 at 09:56
  • Also, beware CoW - it has bad characteristics in a multi-threaded environment (which is why I believe CoW is now outlawed for `std::string`). – Martin Bonner supports Monica Oct 28 '16 at 09:57

2 Answers2

8

You need to initialize the std::shared_ptr inside the union:

union_tmp()
: ptr{} // <--
{}

Otherwise, ptr remains uninitialized, and calling its assignment operator triggers undefined behaviour.

Quentin
  • 62,093
  • 7
  • 131
  • 191
7

I would use std::variant for safe C++ "unions" (or boost::variant if std::variant is not available for you).

E.g. you may try:

std::variant<int, std::shared_ptr<std::vector<int>>> v;
v = std::make_shared<std::vector<int>>();
Mr.C64
  • 41,637
  • 14
  • 86
  • 162
  • I'm not sure about if it's valid to use class with those things as a member, there's an example showing how to use `std::string` and `std::vector` to be the members of union. It seems it's valid, but very tedious. Please correct any of my mistake, thanks. Read here: http://en.cppreference.com/w/cpp/language/union – Marson Mao Oct 28 '16 at 09:55
  • @MarsonMao: I still think variant is better (safer, higher level, less error/bug prone). – Mr.C64 Oct 28 '16 at 10:01
  • I agree, this answer has the same aspect as you. http://stackoverflow.com/a/3521998/649322 – Marson Mao Oct 28 '16 at 10:05