Reputation: 5850
I have a class that contains a boost::shared_array member. The other members are not dynamic - just a bunch of ints, no pointers. I would expect that the default copy constructor for such a class would be fine.
This is my assumption:
Let's say I have an instance of this class, orig.
orig's shared_array member has a reference count of 1.
Now I create a copy of orig:
copy = orig;
I now expect both copy and orig to have shared_arrays that point to the same underlying memory, each with a reference count of 2.
Is the above correct?
I'm intimidated by various people who warn against the default copy constructor when there is a boost::shared_* member - but I can never find an explanation why the default would/could be bad. For example, here's a comment by someone who says an explicit copy/assignment should be defined, but no explanation why:
https://stackoverflow.com/a/716112/629530
Can someone clarify when a copy constructor and assignment operator need to be defined for a class that contains boost::shared_* (shared_array and shared_ptr) members?
Upvotes: 1
Views: 285
Reputation: 50044
The following class uses the Pimpl Idiom in combination with a shared_ptr:
class location
{
struct impl
{
double _latitude;
double _longitude;
};
std::shared_ptr<impl> _impl;
public:
location(double latitude, double longitude)
: _impl{new impl{latitude, longitude}}
{ }
void move_to(double latitude, double longitude)
{
_impl->_latitude = latitude;
_impl->_longitude = longitude;
}
// ...
};
The code compiles and works. However, there is a strange behaviour:
location london{51.51, 0.12};
location paris = london;
paris.move_to(48.86, 2.35);
std::cout << "London: " << london << '\n'; // prints 48.86/2.35
Changing the copy of an object also affected the original object. In this case, it is better to use std::unique_ptr
instead of std::shared_ptr
, because we would have been forced to write our own copy constructor.
There are also cases in which the behaviour of std::shared_ptr
is desired. Let's add a member variable metric
that will be used to calculate the distance between two locations (because there might be different strategies for calculating distances):
std::shared_ptr<metric> _metric;
double operator-(const location& rhs) const
{
return _metric->distance(*_impl, *rhs->_impl);
}
In this case a std::shared_ptr
works perfectly, because the metric is not part of the perceived state of the location, and there is no way to change the metric.
Upvotes: 1