Pointer Constructor in C++ - c++

I'm asked to write a SmartPointer class. One of the constructors takes a pointer variable, and I assume that I should simply copy the pointer to the relevant variable. But when I try, I get a segmentation error. Here is the content of the header file and my implementation of Pointer Constructor.
class ReferenceCount {
public:
size_t AddRef() {
return ++count;
}
size_t Release() {
return --count;
}
size_t getCount() const {
return count;
}
private:
size_t count = 0; // Reference count
};
template<typename T>
class SmartPointer {
private:
void free();
// pointer to actual data
T *dataPointer;
// Reference count
ReferenceCount *referenceCount;
public:
//Constructor
SmartPointer();
// Copy constructor
SmartPointer(const SmartPointer<T> &sp);
explicit SmartPointer(T *pValue);
// Assignment operator
SmartPointer<T> &operator=(const SmartPointer<T> &sp);
SmartPointer<T> &operator=(T *pValue);
// Destructor
~SmartPointer();
T &operator*() const;
T *operator->() const;
T *get() const;
ReferenceCount *getReferenceCount() const;
};
The constructor:
template<typename T>
SmartPointer<T>::SmartPointer(T *pValue) {
dataPointer = pValue;
referenceCount = nullptr;
}

You appear to be writing something similar to shared_ptr<T>.
For a shared_ptr-like smart pointer, each smart pointer has both a pointer-to-object and a pointer-to-control-block.
When you are constructed with a pointer-to-object, you are responsible to create the control block.
In your case, your control block name is ReferenceCount.
So add a new ReferenceCount to that constructor. Probably start it off with a count of 1.

Related

error: binding 'const ...' to reference of type '...&' discards qualifiers

I am trying to save an instance of my custom class to a vector, but I get the following error during compilation:
error: binding 'const anil::cursor_list' to reference of type 'anil::cursor_list&' discards qualifiers
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
Could you help me figure what I'm doing wrong?
The snippet of code that triggers this is as follows:
std::vector<anil::cursor_list> strongly_connected_components;
anil::cursor_list strongly_connected_component_list;
strongly_connected_components.push_back(strongly_connected_component_list);
The declaration for this class is as follows:
#include <cstddef>
#include <iostream>
namespace anil {
class cursor_list_node {
private:
int data;
cursor_list_node* next;
cursor_list_node* previous;
friend class cursor_list;
};
class cursor_list {
private:
// Data:
int m_index;
int m_size;
cursor_list_node* front;
cursor_list_node* back;
cursor_list_node* cursor;
int m_backup_index;
cursor_list_node* backup_cursor;
// Functions:
void delete_list();
public:
cursor_list() : m_index(-1), m_size(0), front(nullptr), back(nullptr),
cursor(nullptr), m_backup_index(-1), backup_cursor(nullptr) {}
cursor_list(cursor_list& copied_list);
bool is_empty();
int size();
int index();
int front_data();
int back_data();
int cursor_data();
bool operator==(cursor_list& rhs); // rhs = right hand side
cursor_list& operator= (cursor_list& rhs); // rhs = right hand side
friend std::ostream& operator<<(std::ostream& out, cursor_list& rhs); // rhs = right hand side
void clear();
void move_cursor_front();
void move_cursor_back();
void move_cursor_prev();
void move_cursor_next();
void save_cursor_state();
void restore_cursor_state();
void prepend(int new_data);
void append(int new_data);
void insert_before_cursor(int new_data);
void insert_after_cursor(int new_data);
void delete_front();
void delete_back();
void delete_cursor();
~cursor_list();
};
}
Lastly, the constructors for the cursor_list class are as follows:
cursor_list() : m_index(-1), m_size(0), front(nullptr), back(nullptr),
cursor(nullptr), m_backup_index(-1), backup_cursor(nullptr) {}
anil::cursor_list::cursor_list(cursor_list& copied_cursor_list) {
this->m_index = -1;
this->m_size = 0;
this->front = nullptr;
this->back = nullptr;
this->cursor = nullptr;
this->m_backup_index = -1;
this->backup_cursor = nullptr;
if (copied_cursor_list.is_empty() == false) {
for (cursor_list_node* it = copied_cursor_list.front; it != nullptr;
it = it->next) {
this->append(it->data);
}
}
}
Edit:
By following prog-fh's explanations and suggestions, I was able to solve the problem described above.
I achieved this by changing the parameter for the copy constructor from cursor_list& copied_cursor_list to const cursor_list& copied_cursor_list and changing the pointer that I used to copy the values of the list from cursor_list_node* it to const cursor_list_node* it.
push_back() makes a copy, but your copy-constructor expects a cursor_list& copied_cursor_list parameter.
The parameter should be const cursor_list& copied_cursor_list.
(See the documentation, the parameter for push_back() is const &).
Actually, the problem is similar with the copy-assign operator (should be cursor_list& operator= (const cursor_list& rhs);).
By the way, your cursor_list type should probably have some const-qualified member functions (is_empty(), size()...) in order to make them usable on an immutable object.
One should consider const-correctness from the beginning; it is difficult to fix it afterwards.
To answer the question in the comments, if the copy constructor was anil::cursor_list::cursor_list(const cursor_list& copied_cursor_list) (as expected), you would have a problem when invoking copied_cursor_list.is_empty() because copied_cursor_list is supposed to be const but the is_empty() member-function does not make the promise « I won't mutate *this ».
In order to fix this, you need to declare (and define as well) bool is_empty() const; (the const at the end of the prototype applies to *this).

Build a wrapper-class for a pointer to pointer in c++

I am trying to create a small wrapper-class that lets me use a pointer to a pointer like
it was just a normal pointer(just for convenience).
I came up with the following code:
template<typename T>
class PtrPtr
{
public:
PtrPtr() = default;
PtrPtr(const T** ptr) : m_ptr(ptr) { }
inline void operator =(const T** ptr) { m_ptr = ptr; }
inline void operator =(T** ptr) { m_ptr = ptr; }
inline operator T*() const { return (*m_ptr); }
inline T** get() const { return m_ptr; }
private:
T** m_ptr;
};
I thought the operator inline operator T*() const { return (*m_ptr); } would
make it possible to use the class as if it were a pointer to T, however it doesn't seem to work
when I try to access T's elements with the following syntax:
PtrPtr<myStruct> ptr = function that returns a pointer to pointer to myStruct;
ptr->some member of myStruct; <-Gives an error
static_cast<myStruct*>(ptr)->some member of myStruct; <-works but obviously tedious syntax
Note that when I specifically cast "PtrPtr ptr" to a T* and then try to access its
members with the "->"-operator it seems to work.
Any Ideas if it is possible to acheive a clean syntax here?
The solution is to over load the ->-operator.
This thread explains how it is done.

Problems with implementation of unique_ptr's move constructor

I'm trying to write a unique_ptr implementation. I'm struggling with writing a move constructor. Here are my problems:
When I mark the move constructor as default, my resource is deleted twice, when I move assign a pointer (auto foo2 = std::move(foo); below) - why?
When I'm trying to assign the underlying pointer in the move constructor like this *rhs = nullptr (see implementation below), the compiler says *rhs is an rvalue and that I cannot assign anything to it.
Finally, rhs.m_ptr = nullptr works. Why does it work, when *rhs = nullptr doesn't?
My code:
#include <iostream>
namespace my
{
template <class T>
class unique_ptr
{
public:
unique_ptr()
{
m_ptr = new T;
}
unique_ptr(const unique_ptr&) = delete;
// move constructor
unique_ptr(unique_ptr&& rhs) // = default deletes m_ptr twice
{
m_ptr = *rhs;
rhs.m_ptr = nullptr; // *rhs = nullptr doesn't work (*rhs is an rvalue)
}
~unique_ptr()
{
delete m_ptr;
}
T* operator->()
{
return m_ptr;
}
T* operator*()
{
return m_ptr;
}
unique_ptr& operator=(const unique_ptr&) = delete;
// no move assignment yet
private:
T* m_ptr;
};
} // namespace my
struct Foo
{
Foo()
{
std::cout << "Foo" << std::endl;
}
~Foo()
{
std::cout << "~Foo" << std::endl;
}
void printHello()
{
std::cout << "Hello" << std::endl;
}
};
int main()
{
my::unique_ptr<Foo> foo;
foo->printHello();
auto foo2 = std::move(foo);
return 0;
}
On a side note, apparently I can pass a unique_ptr without any template parameter to methods inside the unique_ptr class template. Does compiler just assume it's T?
Please discard any other implementation faults that don't relate to the described problems. It's work in progress.
1) The default move constructor doesn't know about the semantics of your class. So it moves the pointer rhs, but it will not reset the other pointer, which will get deleted as well in the other destructor.
2) *rhs calls operator* and returns a temporary/rvalue T*, a copy of the internal pointer, and is not consistent with the usual operator* which should return a T& or a const T&.
3) see 2. you are returning a temporary object.
So finally, what you should have:
unique_ptr(unique_ptr&& rhs) // = default deletes m_ptr twice
: m_ptr(rhs.m_ptr)
{
rhs.m_ptr = nullptr; // *rhs = nullptr doesn't work (*rhs is an rvalue)
}
T& operator*() {return *m_ptr;}
const T& operator*() const {return *m_ptr;}
And so on.
You're trying too hard. You don't have to go through the external interface. Just assign values:
m_ptr = rhs.m_ptr;
rhs.m_ptr = nullptr;
In addition, operator*() should return a T&, not a T*.

Trying to figure out when destructors get called

Below I have a class that keeps a reference count and a class that encapsulates a pointer to another object.
When class Ptr no longer has any objects attached to it, I want to deallocate. This entails deleting the object and the reference count. It is signaled when the value of ptrcnt hits zero.
My Ptr_count class has a destructor which does its part of the deallocation. I know that this destructor will get called when the destructor for Ptr gets called, and it will free up the memory accordingly. However, I'm not so sure it gets called when the assignment operator of Ptr gets called and the code if(--refptr == 0) { delete p; } gets executed.
There is a piece of code commented out in Ptr_count. If I use this instead of the destructor, the deallocation will occur any time the value of refptr goes to zero.
My question is, is there a way for the destructor to be called during the assignment operation in Ptr or would I need to use the code in Ptr_count that is commented out in order to get proper memory deallocation?
Obviously the destructor will be called when I exit the program and the memory will be freed one way or the other but while the program is running, I think that in that instance, the reference pointer can keep decrementing even after it hits zero and that memory will still be around.
class Ptr_count {
public:
Ptr_count() : ptrcnt(new size_t(1)) { }
~Ptr_count()
{
if(ptrcnt && *ptrcnt <= 0)
delete ptrcnt;
}
size_t operator++() const
{
++(*ptrcnt);
return *ptrcnt;
}
size_t operator--() const
{
--(*ptrcnt);
/*
if(*ptrcnt == 0) {
delete ptrcnt;
return 0;
}
*/
if(ptrcnt)
return *ptrcnt;
else
return 0;
}
operator bool() const
{
return ptrcnt;
}
size_t operator*() const
{
return *ptrcnt;
}
private:
size_t* ptrcnt;
};
template <class T> class Ptr {
public:
Ptr() : p(0) {}
Ptr(T* t) : p(t) {}
Ptr(const Ptr& h) : p(h.p), refptr(h.refptr) { ++refptr; }
Ptr& operator=(const Ptr& rhs)
{
++(rhs.refptr);
if(--refptr == 0) {
delete p;
}
refptr = rhs.refptr;
p = rhs.p;
return *this;
}
~Ptr()
{
if(--refptr == 0) {
delete p;
}
}
operator bool() const { return p; }
private:
T* p;
Ptr_count refptr;
};
EDIT::
Alternatively, if class Ptr_count had it's own assignment operator, would this be a work around to the problem? If I added the below code to Ptr_count, it seems like I may be able to free the memory when the reference count reaches 0 during assignment.
void operator=(const Ptr_count& rhs)
{
if(ptrcnt == 0)
delete ptrcnt;
ptrcnt = rhs.ptrcnt;
}
First of all, if this is for self-teaching only go on. Else stop what you are doing and start using std::shared_ptr / std::unique_ptr / std::weak_ptr or if you can't use C++11 std::auto_ptr.
Now to your code:
1) It would be safer and much more natural to increment your reference count in the copy constructor Ptr_count instead of the copy constructor of Ptr, since the purpose of Ptr_count class is to manage the reference count.
You can remove Ptr's copy constructor entirely after doing so.
2) There is an unnecessary check in the assignment operator of Ptr:
// Counter *must* be greater than 0 here, else p is 0 anyways.
Ptr& Ptr::operator=(const Ptr& rhs)
{
++(rhs.refptr); // Increment your counter to 2 or above.
if(--refptr == 0) { // Decrement your counter to 1 or above.
delete p; // Never get here.
}
refptr = rhs.refptr;
p = rhs.p;
return *this;
}
3) Your biggest problem is that you are overwriting refptr and p in the assignment operator.
Ptr& operator=(Ptr const& rhs)
{
Ptr temp(rhs);
std::swap(refptr, temp.refptr);
std::swap(p, temp.p);
return *this;
}
should fix that.
4) Your decrement operator of Ptr_count is somewhat broken.
size_t Ptr_count::operator--() const
{
--(*ptrcnt); // Access address stored in ptrcnt.
if(ptrcnt) // Test if address is valid.
return *ptrcnt;
else
return 0;
}
If ptrcnt was 0 when calling this method you get an access violation because of --(*ptrcnt). Anyway, this should not be necessary, simply remove it:
size_t Ptr_count::operator--() const
{
return --(*ptrcnt);
}
tl;dr
Because code says more than 1000 words, the complete code:
class Ptr_count {
public:
Ptr_count() : ptrcnt(new size_t(1)) { }
Ptr_count(Ptr_count const& rhs) : ptrcnt(rhs.ptrcnt) { ++(*this); }
~Ptr_count()
{
if(ptrcnt && *ptrcnt <= 0)
delete ptrcnt;
}
size_t operator++()
{
return ++(*ptrcnt);
}
size_t operator--()
{
return --(*ptrcnt);
}
operator bool() const
{
return ptrcnt;
}
size_t operator*() const
{
return *ptrcnt;
}
private:
size_t* ptrcnt;
};
template <class T> class Ptr {
public:
Ptr() : p(0) {}
Ptr(T* t) : p(t) {}
Ptr& operator=(Ptr const& rhs)
{
Ptr temp(rhs);
std::swap(refptr, temp.refptr);
std::swap(p, temp.p);
return *this;
}
~Ptr()
{
if(--refptr == 0)
delete p;
}
operator bool() const { return p; }
private:
T* p;
Ptr_count refptr;
};
I think your question primarily boils down to: does this assignment call the destructor of the counter?
refptr = rhs.refptr;
The answer is no. Personally, I would be inclined to actually not wrap the counter code into a separate class and rather have it done in the Ptr class directly. Also, I think my canonical way to implement the assignment operator would take care of the correct behavior:
Ptr& Ptr::operator(Ptr other) {
this->swap(other);
return *this;
}
void Ptr::swap(Ptr& other) {
std::swap(this->p, other.p);
this->ptrcnt.swap(other.ptrcnt);
}
void Ptr_count::swap(Ptr_count& other) {
std::swap(this->ptrcnt, other.ptrcnt);
}
That said, although a simple implementation of a reference counted pointer is a fun interview question, I strong recommend to never actually implement a reference counted pointer [unless you happen to also implement the rest of the standard C++ library] and just use std::shared_ptr<T>: apart from having worked out the nitty gritty details on how to manage the count, this class implements a couple of pretty cool features which go way beyond your simple reference counted pointer and many of these features actually happen to be needed in real code.

STL-friendly pImpl class?

I am maintaining a project that can take a considerable time to build so am trying to reduce dependencies where possible. Some of the classes could make use if the pImpl idiom and I want to make sure I do this correctly and that the classes will play nicely with the STL (especially containers.) Here is a sample of what I plan to do - does this look OK? I am using std::auto_ptr for the implementation pointer - is this acceptable? Would using a boost::shared_ptr be a better idea?
Here is some code for a SampleImpl class that uses classes called Foo and Bar:
// SampleImpl.h
#ifndef SAMPLEIMPL_H
#define SAMPLEIMPL_H
#include <memory>
// Forward references
class Foo;
class Bar;
class SampleImpl
{
public:
// Default constructor
SampleImpl();
// Full constructor
SampleImpl(const Foo& foo, const Bar& bar);
// Copy constructor
SampleImpl(const SampleImpl& SampleImpl);
// Required for std::auto_ptr?
~SampleImpl();
// Assignment operator
SampleImpl& operator=(const SampleImpl& rhs);
// Equality operator
bool operator==(const SampleImpl& rhs) const;
// Inequality operator
bool operator!=(const SampleImpl& rhs) const;
// Accessors
Foo foo() const;
Bar bar() const;
private:
// Implementation forward reference
struct Impl;
// Implementation ptr
std::auto_ptr<Impl> impl_;
};
#endif // SAMPLEIMPL_H
// SampleImpl.cpp
#include "SampleImpl.h"
#include "Foo.h"
#include "Bar.h"
// Implementation definition
struct SampleImpl::Impl
{
Foo foo_;
Bar bar_;
// Default constructor
Impl()
{
}
// Full constructor
Impl(const Foo& foo, const Bar& bar) :
foo_(foo),
bar_(bar)
{
}
};
SampleImpl::SampleImpl() :
impl_(new Impl)
{
}
SampleImpl::SampleImpl(const Foo& foo, const Bar& bar) :
impl_(new Impl(foo, bar))
{
}
SampleImpl::SampleImpl(const SampleImpl& sample) :
impl_(new Impl(*sample.impl_))
{
}
SampleImpl& SampleImpl::operator=(const SampleImpl& rhs)
{
if (this != &rhs)
{
*impl_ = *rhs.impl_;
}
return *this;
}
bool SampleImpl::operator==(const SampleImpl& rhs) const
{
return impl_->foo_ == rhs.impl_->foo_ &&
impl_->bar_ == rhs.impl_->bar_;
}
bool SampleImpl::operator!=(const SampleImpl& rhs) const
{
return !(*this == rhs);
}
SampleImpl::~SampleImpl()
{
}
Foo SampleImpl::foo() const
{
return impl_->foo_;
}
Bar SampleImpl::bar() const
{
return impl_->bar_;
}
You should consider using copy-and-swap for assignment if it's possible that Foo or Bar might throw as they're being copied. Without seeing the definitions of those classes, it's not possible to say whether they can or not. Without seeing their published interface, it's not possible to say whether they will in future change to do so, without you realising.
As jalf says, using auto_ptr is slightly dangerous. It doesn't behave the way you want on copy or assignment. At a quick look, I don't think your code ever allows the impl_ member to be copied or assigned, so it's probably OK.
If you can use scoped_ptr, though, then the compiler will do that tricky job for you of checking that it's never wrongly modified. const might be tempting, but then you can't swap.
There are a couple of problems with the Pimpl.
First of all, though not evident: if you use Pimpl, you will have to define the copy constructor / assignment operator and destructor (now known as "Dreaded 3")
You can ease that by creating a nice template class with the proper semantic.
The problem is that if the compiler sets on defining one of the "Dreaded 3" for you, because you had used forward declaration, it does know how to call the "Dreaded 3" of the object forward declared...
Most surprising: it seems to work with std::auto_ptr most of the times, but you'll have unexpected memory leaks because the delete does not work. If you use a custom template class though, the compiler will complain that it cannot find the needed operator (at least, that's my experience with gcc 3.4.2).
As a bonus, my own pimpl class:
template <class T>
class pimpl
{
public:
/**
* Types
*/
typedef const T const_value;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
/**
* Gang of Four
*/
pimpl() : m_value(new T) {}
explicit pimpl(const_reference v) : m_value(new T(v)) {}
pimpl(const pimpl& rhs) : m_value(new T(*(rhs.m_value))) {}
pimpl& operator=(const pimpl& rhs)
{
pimpl tmp(rhs);
swap(tmp);
return *this;
} // operator=
~pimpl() { delete m_value; }
void swap(pimpl& rhs)
{
pointer temp(rhs.m_value);
rhs.m_value = m_value;
m_value = temp;
} // swap
/**
* Data access
*/
pointer get() { return m_value; }
const_pointer get() const { return m_value; }
reference operator*() { return *m_value; }
const_reference operator*() const { return *m_value; }
pointer operator->() { return m_value; }
const_pointer operator->() const { return m_value; }
private:
pointer m_value;
}; // class pimpl<T>
// Swap
template <class T>
void swap(pimpl<T>& lhs, pimpl<T>& rhs) { lhs.swap(rhs); }
Not much considering boost (especially for the cast issues), but there are some niceties:
proper copy semantic (ie deep)
proper const propagation
You still have to write the "Dreaded 3". but at least you can treat it with value semantic.
EDIT: Spurred on by Frerich Raabe, here is the lazy version, when writing the Big Three (now Four) is a hassle.
The idea is to "capture" information where the full type is available and use an abstract interface to make it manipulable.
struct Holder {
virtual ~Holder() {}
virtual Holder* clone() const = 0;
};
template <typename T>
struct HolderT: Holder {
HolderT(): _value() {}
HolderT(T const& t): _value(t) {}
virtual HolderT* clone() const { return new HolderT(*this); }
T _value;
};
And using this, a true compilation firewall:
template <typename T>
class pimpl {
public:
/// Types
typedef T value;
typedef T const const_value;
typedef T* pointer;
typedef T const* const_pointer;
typedef T& reference;
typedef T const& const_reference;
/// Gang of Five (and swap)
pimpl(): _holder(new HolderT<T>()), _p(this->from_holder()) {}
pimpl(const_reference t): _holder(new HolderT<T>(t)), _p(this->from_holder()) {}
pimpl(pimpl const& other): _holder(other->_holder->clone()),
_p(this->from_holder())
{}
pimpl(pimpl&& other) = default;
pimpl& operator=(pimpl t) { this->swap(t); return *this; }
~pimpl() = default;
void swap(pimpl& other) {
using std::swap;
swap(_holder, other._holder);
swap(_p, other._p)
}
/// Accessors
pointer get() { return _p; }
const_pointer get() const { return _p; }
reference operator*() { return *_p; }
const_reference operator*() const { return *_p; }
pointer operator->() { return _p; }
const_pointer operator->() const { return _p; }
private:
T* from_holder() { return &static_cast< HolderT<T>& >(*_holder)._value; }
std::unique_ptr<Holder> _holder;
T* _p; // local cache, not strictly necessary but avoids indirections
}; // class pimpl<T>
template <typename T>
void swap(pimpl<T>& left, pimpl<T>& right) { left.swap(right); }
I've been struggling with the same question. Here's what I think the answer is:
You can do what you are suggesting, so long as you define the copy and assignment operators to do sensible things.
It's important to understand that the STL containers create copies of things. So:
class Sample {
public:
Sample() : m_Int(5) {}
void Incr() { m_Int++; }
void Print() { std::cout << m_Int << std::endl; }
private:
int m_Int;
};
std::vector<Sample> v;
Sample c;
v.push_back(c);
c.Incr();
c.Print();
v[0].Print();
The output from this is:
6
5
That is, the vector has stored a copy of c, not c itself.
So, when you rewrite it as a PIMPL class, you get this:
class SampleImpl {
public:
SampleImpl() : pimpl(new Impl()) {}
void Incr() { pimpl->m_Int++; }
void Print() { std::cout << m_Int << std::endl; }
private:
struct Impl {
int m_Int;
Impl() : m_Int(5) {}
};
std::auto_ptr<Impl> pimpl;
};
Note I've mangled the PIMPL idiom a bit for brevity. If you try to push this into a vector, it still tries to create a copy of the SampleImpl class. But this doesn't work, because std::vector requires that the things it store provide a copy constructor that doesn't modify the thing it's copying.
An auto_ptr points to something that is owned by exactly one auto_ptr. So when you create a copy of an auto_ptr, which one now owns the underlying pointer? The old auto_ptr or the new one? Which one is responsible for cleaning up the underlying object? The answer is that ownership moves to the copy and the original is left as a pointer to nullptr.
What auto_ptr is missing that prevents its use in a vector is copy constructor taking a const reference to the thing being copied:
auto_ptr<T>(const auto_ptr<T>& other);
(Or something similar - can't remember all the template parameters). If auto_ptr did provide this, and you tried to use the SampleImpl class above in the main() function from the first example, it would crash, because when you push c into the vector, the auto_ptr would transfer ownership of pimpl to the object in the vector and c would no longer own it. So when you called c.Incr(), the process would crash with a segmentation fault on the nullptr dereference.
So you need to decide what the underlying semantics of your class are. If you still want the 'copy everything' behaviour, then you need to provide a copy constructor that implements that correctly:
SampleImpl(const SampleImpl& other) : pimpl(new Impl(*(other.pimpl))) {}
SampleImpl& operator=(const SampleImpl& other) { pimpl.reset(new Impl(*(other.pimpl))); return *this; }
Now when you try to take a copy of a SampleImpl, you also get a copy of its Impl struct, owned by the copy SampleImpl. If you're taking an object that had lots of private data members and was used in STL containers and turning it into a PIMPL class, then this is probably what you want, as it provides the same semantics as the original. But note that pushing the object into a vector will be considerably slower as there is now dynamic memory allocation involved in copying the object.
If you decide you don't want this copy behaviour, then the alternative is for the copies of SampleImpl to share the underlying Impl object. In this case, it's not longer clear (or even well-defined) which SampleImpl object owns the underlying Impl. If ownership doesn't clearly belong in one place, then std::auto_ptr is the wrong choice for storing it
and you need to use something else, probably a boost template.
Edit: I think the above copy constructor and assignment operator are exception-safe so long as ~Impl doesn't throw an exception. This should always be true of your code anyway.