Below, you can find an example of a std::unique_ptr-PIMPled type with move semantics, which shows what I tend to use most of the time:
foo.h
Code: Select all
/*
(c) 2012 +++ Filip Stoklas, aka FipS, http://www.4FipS.com +++
THIS CODE IS FREE - LICENSED UNDER THE MIT LICENSE
ARTICLE URL: http://forums.4fips.com/viewtopic.php?f=3&t=715
*/
#ifndef FS_HEADER__foo_h__GUARD
#define FS_HEADER__foo_h__GUARD
#include <memory>
class Foo // non-copyable, movable, PIMPLed type
{
public:
Foo();
~Foo(); // DTOR required when PIMPL uses 'std::unique_ptr'!
Foo(Foo&& rhs); // move constructor
Foo& operator=(Foo&& rhs); // move assignment
void bar();
private:
Foo(const Foo&); // non-copyable ('= delete' in C++11)
Foo& operator=(const Foo&); // non-copyable ('= delete' in C++11)
// a complete type is not required in the case of 'std::unique_ptr',
// however, 'Foo' needs to define a DTOR with its implementation in
// CPP, otherwise it doesn't compile (note that this is not required
// in the case of 'std::shared_ptr')
class Impl;
std::unique_ptr<Impl> _impl;
};
#endif // FS_HEADER__foo_h__GUARD
Code: Select all
/*
(c) 2012 +++ Filip Stoklas, aka FipS, http://www.4FipS.com +++
THIS CODE IS FREE - LICENSED UNDER THE MIT LICENSE
ARTICLE URL: http://forums.4fips.com/viewtopic.php?f=3&t=715
*/
#include "foo.h"
#include <iostream>
class Foo::Impl
{
public:
Impl() {}
void bar() { std::cout << "Foo::Impl::bar();\n"; }
private:
Impl(const Impl&); // non-copyable ('= delete' in C++11)
Impl& operator=(const Impl&); // non-copyable ('= delete' in C++11)
};
// forwards:
Foo::Foo() : _impl(new Impl) {}
Foo::~Foo() {} // required by 'std::unique_ptr'!
Foo::Foo(Foo&& rhs) : _impl(std::move(rhs._impl)) {}
Foo& Foo::operator=(Foo&& rhs) { _impl = std::move(rhs._impl); return *this; }
void Foo::bar() { _impl->bar(); }
Code: Select all
/*
(c) 2012 +++ Filip Stoklas, aka FipS, http://www.4FipS.com +++
THIS CODE IS FREE - LICENSED UNDER THE MIT LICENSE
ARTICLE URL: http://forums.4fips.com/viewtopic.php?f=3&t=715
*/
#include "foo.h"
int main()
{
Foo foo;
foo.bar();
Foo bar = std::move(foo); // moves, steals '_impl' from 'foo'
bar.bar();
//Foo baz = bar; // DOESN'T COMPILE!, 'Foo' is non-copyable
}
// output:
// Foo::Impl::bar();
// Foo::Impl::bar();