|
Boost : |
From: Aleksey Gurtovoy (alexy_at_[hidden])
Date: 2001-05-03 05:55:16
John Maddock wrote:
> This problem is not related to compressed_pair specifically,
> but will occur whenever an assignment to an empty base
> class occurs.
This is a known issue; the problem also appears if you let the compiler to
generate the derived class' assignment operator for you:
struct something_empty {};
struct luckless : something_empty
{
std::string text;
#if 0 // 1 here fixes the problem
luckless& operator=(const luckless& other)
{
text = other.text;
return *this;
}
#endif
};
int main()
{
luckless ll1;
luckless ll2;
ll1 = ll2; // crash here
return 0;
}
A subtle detail here is that you will see the problem only if the very first
member of your derived class has non-trivial assignment operator
("non-trivial" not in sense how the standard defines the term, but in some
rather specific way - the one that manages some resources, e.g. memory); for
example, the following definition of 'luckless' passes the above test just
fine (and assignment indeed does the right thing):
struct luckless : something_empty
{
int i;
std::string text;
};
and all 4 definitions below reproduce the problem with 100% probability (at
least on my system):
struct nontrivial
{
nontrivial() : ptr_(new int(5)) {}
nontrivial(nontrivial const& other) : ptr_(new int(*other.ptr_)) {}
nontrivial& operator=(nontrivial const& other)
{
nontrivial(other).swap(*this);
return *this;
}
nontrivial& swap(nontrivial& other)
{
std::auto_ptr<int> ptr(ptr_);
ptr_ = other.ptr_;
other.ptr_ = ptr;
return *this;
}
std::auto_ptr<int> ptr_;
};
1)
struct luckless : something_empty
{
nontrivial m;
};
2) typedef boost::compressed_pair<std::string, something_empty> luckless;
3) typedef boost::compressed_pair<nontrivial, something_empty> luckless;
4)
struct luckless : boost::equality_comparable<luckless>
{
nontrivial m;
};
So things are indeed not very good. Of course, a workaround of the
compressed_pair's assignment problem (ll1 = ll2;) is to explicitly define
the copy assignment operator for it; but I don't see what we can do about
the original problem:
boost::compressed_pair<int, empty_class> cp;
cp.second() = some_empty_class_value;
and cases like 4-th one from the above code, except documenting the issues
so users could be aware of them. (well, as for 'compressed_pair', we could
make MSVC versions of the class 'first' or/and 'second' method(s) to return
a copy of the empty class instead of a reference to it , but as I see it
now, it creates even more problems). hmm.., probably I wasn't very helpful
:(...
Aleksey
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk