By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,929 Members | 1,245 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,929 IT Pros & Developers. It's quick & easy.

Safe union of std::vectors

P: n/a
I'd like to do something along these lines:

struct foo
{
int i1_;
int i2_;
};

struct bar
{
double d1_;
double d2_;
};

typedef std::vector<foo> vectorFoo;
typedef std::vector<bar> vectorBar;

union vectorAll
{
vectorFoo foo_;
vectorBar bar_;
};

static vectorAll myVectorAll;
....
foo myFoo;
myVectorAll.foo_.push_back(myFoo);
myVectorAll.foo_.clear();
....
bar myBar;
myVectorAll.bar_.push_back(myBar);
myVectorAll.bar_.clear();

But a) I'm fairly sure that this isn't valid C++ because std::vector
must have a constructor, b) it seems very unsafe. and c) it precludes
sensible requirements such as clearing myVectorAll without knowing what
type is in it. (Intuitively one might want to be able to do a
myVectorAll.clear());

Given that one of my target compilers is too uncompliant to compile
boost, I can't use boost::any for this. What are my other options?

--
Simon Elliott http://www.ctsn.co.uk
Jul 23 '05 #1
Share this Question
Share on Google+
5 Replies


P: n/a
"Simon Elliott" <Simon at ctsn.co.uk> wrote in message
news:41***********************@news.gradwell.net.. .
I'd like to do something along these lines:

struct foo
{
int i1_;
int i2_;
};

struct bar
{
double d1_;
double d2_;
};

typedef std::vector<foo> vectorFoo;
typedef std::vector<bar> vectorBar;

union vectorAll
{
vectorFoo foo_;
vectorBar bar_;
};

static vectorAll myVectorAll;
...
foo myFoo;
myVectorAll.foo_.push_back(myFoo);
myVectorAll.foo_.clear();
...
bar myBar;
myVectorAll.bar_.push_back(myBar);
myVectorAll.bar_.clear();

But a) I'm fairly sure that this isn't valid C++ because std::vector
must have a constructor,
It's invalid because std::vector *does* have a (non-trivial)
constructor (as well as other precluded member functions).
(C&V below)
b) it seems very unsafe.
Well, I suppose it you were able to convince a compiler
to create code for it, it would very likely be 'unsafe'. :-)
and c) it precludes
sensible requirements such as
Such as violating the standard's rules. :-)
clearing myVectorAll without knowing what
type is in it. (Intuitively one might want to be able to do a
myVectorAll.clear());
I wouldn't intiut that because the your union has no member
functions.
Given that one of my target compilers is too uncompliant to compile
boost, I can't use boost::any for this. What are my other options?


Don't use a union. :-) How about a function template?
(Of course that's just a guess, without knowing more
about what you're trying to do.)

ISO/IEC 14882:1998(E)

9.5 Unions

1 In a union, at most one of the data members can be active
at any time, that is, the value of at most one of the data
members can be stored in a union at any time. [Note: one
special guarantee is made in order to simplify the use of
unions: If a POD*-union contains several POD*-structs that
share a common initial sequence (9.2), and if an object of
this POD*-union type contains one of the POD*-structs, it is
permitted to inspect the common initial sequence of any of
POD*struct members; see 9.2. ] The size of a union is suffi*-
cient to contain the largest of its data members. Each data
member is allocated as if it were the sole member of a struct.
A union can have member functions (including constructors
and destructors), but not virtual (10.3) functions. A union
shall not have base classes. A union shall not be used as a
base class. An object of a class with a non*-trivial constructor
(12.1), a non-*trivial copy constructor (12.8), a non*-trivial
destructor (12.4), or a non-*trivial copy assignment operator
(13.5.3, 12.8) cannot be a member of a union, nor can an
array of such objects. If a union contains a static data
member, or a member of reference type, the program is ill-*formed.
-Mike
Jul 23 '05 #2

P: n/a

Simon Elliott wrote:
I'd like to do something along these lines:

struct foo {...}
struct bar {...}
typedef std::vector<foo> vectorFoo;
typedef std::vector<bar> vectorBar;

union vectorAll
{
vectorFoo foo_;
vectorBar bar_;
};

static vectorAll myVectorAll;
...
foo myFoo;
myVectorAll.foo_.push_back(myFoo);
myVectorAll.foo_.clear();
...
bar myBar;
myVectorAll.bar_.push_back(myBar);
myVectorAll.bar_.clear();

But a) I'm fairly sure that this isn't valid C++ because std::vector
must have a constructor, b) it seems very unsafe. and c) it precludes
sensible requirements such as clearing myVectorAll without knowing what type is in it. (Intuitively one might want to be able to do a
myVectorAll.clear());

Given that one of my target compilers is too uncompliant to compile
boost, I can't use boost::any for this. What are my other options?


The logical solution is probably to wrap your own vector class
around a union of two pointers, a Foo* and a Bar*. You can use a
shared size member, so you can implement empty() without
differentiating which elements there aren't ;) For most operations
you will have to use a tag, though.

You'd have to add your own push_back overloads, your own iterators,
a foo_begin() and a bar_begin() but it's not too difficult.

BTW, if you're targetting multiple platforms and one is very out
of date, you might want to consider Comeau.

HTH,
Michiel Salters

Jul 23 '05 #3

P: n/a
Simon Elliott wrote:
I'd like to do something along these lines:

struct foo
{
int i1_;
int i2_;
};

struct bar
{
double d1_;
double d2_;
};

typedef std::vector<foo> vectorFoo;
typedef std::vector<bar> vectorBar;

union vectorAll
{
vectorFoo foo_;
vectorBar bar_;
};

static vectorAll myVectorAll;
...
foo myFoo;
myVectorAll.foo_.push_back(myFoo);
myVectorAll.foo_.clear();
...
bar myBar;
myVectorAll.bar_.push_back(myBar);
myVectorAll.bar_.clear();

[...]
Given that one of my target compilers is too uncompliant to compile
boost, I can't use boost::any for this. What are my other options?


Perhaps something like the following might do the job:

class FooBarVector
{
enum VectorType { NONE, FOO, BAR };
public:
FooBarVector() : type_(NONE) { };

~FooBarVector() {
switch(type_) {
case FOO: delete v_.foo_; break;
case BAR: delete v_.bar_; break;
}
type_ = NONE;
}

vectorFoo& foo(){
if (type_ == BAR)
delete v_.bar_;
if (type_ != FOO) {
v_.foo_ = new vectorFoo();
type_ = FOO;
}
return *(v_.foo_);
}

vectorBar& bar(){
if (type_ == FOO)
delete v_.foo_;
if (type_ != BAR) {
v_.bar_ = new vectorBar();
type_ = BAR;
}
return *(v_.bar_);
}
private:
union {
vectorFoo *foo_;
vectorBar *bar_;
} v_;

VectorType type_;
};

// ...
static FooBarVector v;
// ...
Foo myFoo;
v.foo().push_back(myFoo);
v.foo().clear();
// ...
Bar myBar;
v.bar().push_back(myBar);
v.bar().clear();
// ...

As an alternative, you can throw an exception, if foo() is called with
an non-empty bar-Vector (and vice versa).

greetings
Martin
Jul 23 '05 #4

P: n/a
On 02/02/2005, msalters wrote:
The logical solution is probably to wrap your own vector class
around a union of two pointers, a Foo* and a Bar*. You can use a
shared size member, so you can implement empty() without
differentiating which elements there aren't ;) For most operations
you will have to use a tag, though.

You'd have to add your own push_back overloads, your own iterators,
a foo_begin() and a bar_begin() but it's not too difficult.
Yes. I was hoping for a solution that didn't involve vectors of
pointers though.
BTW, if you're targetting multiple platforms and one is very out
of date, you might want to consider Comeau.


I'd like to drop support for BCB3 but can't at the moment. I'm quite
interested in adding Comeau to the list of supported compilers at some
point.

--
Simon Elliott http://www.ctsn.co.uk
Jul 23 '05 #5

P: n/a

Simon Elliott wrote:
On 02/02/2005, msalters wrote:
The logical solution is probably to wrap your own vector class
around a union of two pointers, a Foo* and a Bar*. You can use a
shared size member, so you can implement empty() without
differentiating which elements there aren't ;) For most operations
you will have to use a tag, though.

You'd have to add your own push_back overloads, your own iterators,
a foo_begin() and a bar_begin() but it's not too difficult.
Yes. I was hoping for a solution that didn't involve vectors of
pointers though.


It's not a vector of pointers, just

template< typename T1, typename T2 >
class bi_vector
{
union {
T1* t1_array;
T2* t2_array;
} data;
size_t size;
enum { t1_used, t2_used } type_in_data;
public:
// ...
};
If you want to save memory, you could use a signed integer type
for size, with size > 0 meaning size T1 objects and size < 0
meaning -size T2 objects. Not worth the price if these vectors
are rare, of course.

HTH,
Michiel Salters
BTW, if you're targetting multiple platforms and one is very out
of date, you might want to consider Comeau.


I'd like to drop support for BCB3 but can't at the moment. I'm quite
interested in adding Comeau to the list of supported compilers at

some point.

--
Simon Elliott http://www.ctsn.co.uk


Jul 23 '05 #6

This discussion thread is closed

Replies have been disabled for this discussion.