std::auto_ptr depricated in C++11
=============
#include <memory>
template< class T > class auto_ptr;
template<> class auto_ptr<void>
auto_ptr should not be used in new code. Use unique_ptr instead.
std::unique_ptr since C++11
===============
#include <memory>
template< class T, class Deleter = std::default_delete<T>> class unique_ptr;
template <class T, class Deleter> class unique_ptr<T[],Deleter>;
Moveable (MoveConstructible and MoveAssignable) but not copyable or assignable:
void f()
{
std::unique_ptr<Foo> up(new Foo());
std::unique_ptr<Foo> up2(up);
std::unique_ptr<Foo> up3;
up3 = up;
up3 = std::move(up);
}
Not to accept raw pointers in assignment:
Foo *fooPtr = ... ;
std::unique_ptr<Foo> up(new Foo());
up = fooPtr;
Convertable to boolean:
void f()
{
std::unique_ptr<Foo> up(new Foo());
if ( up )
{
*up;
}
}
Convertible to shared_ptr:
std::unique_ptr<Foo> up(new Foo());
std::shared_ptr<Foo> sp = up;
Use make_unique<> since C++14
std::unique_ptr<T> v1 = std::make_unique<T>();
std::unique_ptr<T> v2 = std::make_unique<T>(x,y,z);
std::unique_ptr<T[]> v3 = std::make_unique<T[]>(5);
Source/sink:
void sink(std::unique_ptr<Foo> p)
{
}
std::unique_ptr<Foo> source()
{
return std::unique_ptr<Foo>(new Foo);
}
void f()
{
auto up = source();
sink(up);
sink(move(up));
return 0;
}
Will this work?:
unique_ptr<Foo> source()
{
std::unique_ptr<Foo> up(new Foo);
return up;
}
Abstract factory pattern example (from Scott Meyers: Effective Modern C++)
class Base { ... };
class Derived1 : public Base { ... };
class Derived2 : public Base { ... };
class Derived3 : public Base { ... };
template <typename... Ts>
std::unique_ptr<Base> makeBase( Ts&&... params) { ... }
void f()
{
auto pBase = makeBase( );
}
Custom deleter:
auto delBase = [](Base *pBase)
{
makeLogEntry(pBase);
delete pBase;
};
template <typename... Ts>
std::unique_ptr<Base, decltype(delBase)> makeBase( Ts&&... params)
{
std::unique_ptr<Base, decltype(delBase)> pBase(nullptr, delBase);
if ( )
{
pBase.reset(new Derived1( std::forward<Ts>(params)...));
}
else if ( )
{
pBase.reset(new Derived2( std::forward<Ts>(params)...));
}
else if ( )
{
pBase.reset(new Derived3( std::forward<Ts>(params)...));
}
return pBase;
}
Size:
- The sizeof(unique_ptr<>) without deleter is == sizeof(raw pointer)
- If there is deleter with state, the size increases
- If no state, then no size penalty (e.g. lambda with no capture).
- If no state, but function pointer is used as deleter -> sizeof(funptr) added
State stored in deleter may increase the size of unique_ptr.
Unique_ptr has two forms:
std::unique_ptr<T>
has operator* and operator->
std::unique_ptr<T[]>
has operator[]
How to emulate boost:scoped_ptr?:
void f()
{
boost::scoped_ptr<Foo> sp(new Foo);
std::unique_ptr<Foo> up(new Foo);
boost::scoped_ptr<Foo> sp2;
std::unique_ptr<Foo> up2;
sp2 = sp;
up2 = up;
sp2 = std::move(sp);
up2 = std::move(up);
}
void f()
{
const std::unique_ptr<Foo> up(new Foo);
std::unique_ptr<Foo> up2;
up2 = std::move(up);
}
The ugly swap:
void f()
{
boost::scoped_ptr<Foo> sp1(new Foo);
const std::unique_ptr<Foo> up1(new Foo);
{
boost::scoped_ptr<Foo> sp2(new Foo);
const std::unique_ptr<Foo> up2(new Foo);
swap(sp1,sp2);
swap(up1,up2);
}
}
Prefer unique_ptr over shared_ptr until you need more owner
- replace auto_ptr when want to use a single ownership pointer
- exception safety for dynamically allocated objects
- using source/sink strategy for controlling object lifetime
- use in standard containers when polymorphic usage is needed
- it is cheap - only the pointer size
Not to use when:
- need downcast (dynamic cast): No special cast operations are provided
std::shared::ptr since C++11
================
#include <memory>
template< class T > class shared_ptr;
Shared ownership with copy semantics (copy constructible and copy assignable)
What about unique_array<> and shared_array<> ?
There is aspecialization for unique_ptr<T[]>.
#include <iostream>
#include <memory>
struct test
{
~test() { std::cout << "test::dtor" << std::endl; }
};
int main()
{
std::unique_ptr<test[]> array(new test[3]);
}
When you run it, you will get this messages.
test::dtor
test::dtor
test::dtor
If you want to use shared_ptr, you should use std::default_delete<T[]>
for deleter since it doesn't have one like shared_ptr<t[]>.
std::shared_ptr<test> array(new test[3], std::default_delete<test[]>());
Issues
======
1. Smart opointers are not polymorphic - they only simalte that with op=, etc.
- Kovariant return types do not work with smart pointers
2. You can still make memory leak - with circulat shared_ptr, etc.
Stroustrup
==========
Owner pointers are better than smart pointers