I have the typical reentrant C style parser, where the parsed data is contained in an union like the following one:
%union {
int number;
const char *string;
Item *item_ptr;
}
I would like to use Shared Pointers instead of normal pointers.
I cannot use std::shared_ptr
because I cannot compile the source code with C++11
, I am also forbidden to use boost::shared_ptr
. Thus, I have my own class SharedPtr
, implementing the desired behaviour.
Unfortunately, I cannot plug the SharedPtr
class within the union as follows:
%union {
int number;
const char *string;
SharedPtr<Item> item_ptr;
}
because I get the following error:
bisonparser.yy:92:20: error: member ‘SharedPtr<Item> YYSTYPE::item_ptr’ with constructor not allowed in union
bisonparser.yy:92:20: error: member ‘SharedPtr<Item> YYSTYPE::item_ptr’ with destructor not allowed in union
bisonparser.yy:92:20: error: member ‘SharedPtr<Item> YYSTYPE::item_ptr’ with copy assignment operator not allowed in union
bisonparser.yy:92:20: note: unrestricted unions only available with -std=c++11 or -std=gnu++11
An alternative could be inserting a level of indirection as follows:
%union {
int number;
const char *string;
SharedPtr<Item> *item_ptr;
}
However, I wonder if there is a much cleaner way to design my project so that I can use my SharedPtr
class directly instead of as a pointer. What are the minimal changes that I have too look for to get to the alternative solution?
The basic problem is that bison's C interface uses unions heavily (from %union) and C unions are pretty incompatible with C++ (pre-C++11 you can't use them at all with non-trivial types and even post C++11 they are hard to use safely).
On possibility is to use Bison's C++ mode, but that is a fairly verbose and wide-ranging change. Alternately, you can (carefully) use raw pointers and other types that are safe to put in a union. You'll need to be very careful to avoid memory leaks however (and use bison's %destructor
to avoid leaks with syntax errors)
Another possibility is to not use %union
at all -- instead use #define YYSTYPE SharedPtr<Item>
to make the stack value a single shared pointer that you'll use everywhere in the code. You need to have your Item
type be a base class with all your other types deriving from it, using virtual functions as appropriate.