auto for type declaration
DESCRIPTION
auto for Type Declaration. Auto variables have the type of their initializing expression: auto x1 = 10; //either syntax is auto y1(20); //fine map< int , string> m; auto i1 = m.begin (); Const/volatile and reference/pointer adornments may be added: - PowerPoint PPT PresentationTRANSCRIPT
auto for Type Declaration
Auto variables have the type of their initializing expression:auto x1 = 10; //either syntax is
auto y1(20); //fine
map<int, string> m;
auto i1 = m.begin();
Const/volatile and reference/pointer adornments may be added:const auto *x2 = &x1;const auto& i2 = m; //i2 is map&
auto for Type Declaration
Type deduction for auto is akin to that for template parameters.
Auto can be used to declare multiple variables:void f(string& s){ auto temp = s, *ptr =&s;}
Each initiation must yield the same deduced type (like template deduction):
auto i = 5, d = 10.33; //error
nullptr
A new keyword, indicates a null pointer. Convertible to any pointer type and to bool, but
nothing else. Can’t be used as an integral value Traditional use of 0 and NULL remain valid.const char * p = nullptr;if (p)int I = nullptr; //errorif (nullptr == 0) //errorint *p1 = nullptr;int *p2 = 0;int *p3 = NULL;if (p1 == p2 == p3) …
nullptr
Only nullptr is unambiguously a pointer:
void f(int *ptr);void f(int val);
…f(nullptr); //f(int*)f(0); //f(int)f(NULL); //probably f(int)
How Smart Are your pointers?
C++98 auto_ptr
TR1 shared_ptr and weak_ptr
C++0x Support for allocators and unique_ptr
auto_ptr
auto_ptr is a smart pointer template that provides auto destruction of dynamically allocated memory when the pointer goes out of scope.
#include <memory> // auto_ptr’s header
class MyValue { . . . }; // Same as before void process(int val) { . . . } // Same as before
auto_ptrint main() { std::auto_ptr<MyValue> p(new MyValue(5)); while(--(*p) >= 0)
{std::cout << "Enter a value: ";int value; std::cin >> value;process(value);
} // An explicit call to delete is no longer necessary
. . . }
output: CTOREnter a value: 6Enter a value: 23Enter a value: 17DTOR
auto_ptr
auto_ptr objects contain an ownership indicator. This is used for management of dynamic memory in the event multiple auto_ptr objects refer to the same element_type object. This is different behavior than conventional deep-copy and reference counting schemes for smart pointers.
auto_ptr usageclass Foo{ public : Foo(int v); ~Foo(); void display(void); private : int m_val; };
Foo::Foo(int v) : m_val(v) { cout << "ctor - " << m_val << endl; }
Foo::~Foo() { cout << "dtor - " << m_val << endl; }
void Foo::display(void){ cout << ”Value = ” << m_val” << endl;}
auto_ptr usageint main() { std::auto_ptr<Foo> p1(new Foo(1)); std::auto_ptr<Foo> p2(new Foo(2)); p1->display(); . . . }
output:ctor - 1ctor – 2Value = 1dtor – 2dtor - 1
auto_ptr
Relinquishing ownership without releasing memory...
int main() { std::auto_ptr<Foo> p1(new Foo(1)); std::auto_ptr<Foo> p2(new Foo(2)); p1.release(); // Memory leak . . . }output: ctor - 1
ctor – 2dtor - 2
auto_ptr
The right way to use release()... int main() { std::auto_ptr<Foo> p1(new Foo(1)); std::auto_ptr<Foo> p2(new Foo(2)); delete p1.release(); . . . }output: ctor - 1
ctor - 2dtor - 1dtor - 2
Ownership
Transfer of ownership… int main() { std::auto_ptr<Foo> p1(new Foo(1));
// p1 owns the object std::auto_ptr<Foo> p2; p2 = p1; // now p2 owns the object std::auto_ptr<Foo> p3(p2);
// now p3 owns it . . . }output: ctor - 1
dtor - 1
Ownershipvoid bar(std::auto_ptr<Foo> ptr){ std::cout << "Some processing" << std::endl;} int main() {
std::auto_ptr<Foo> p1(new Foo(1));std::cout << "Before bar()" << std::endl;bar(p1);std::cout << "After bar()" << std::endl;// What does p1 point to here?
. . .}
output: ctor – 1Before bar()Some processingdtor – 1After bar()
Ownership
Change bar()’s signature to this… void bar(std::auto_ptr<Foo> &ptr) { . . . }
and the problem goes away…
output: ctor – 1Before bar()Some processingAfter bar()dtor – 1
Smart Pointers
Smart pointers simplify resource management. Prevention of leaks. Don’t have to call “delete”
auto_ptr is constraining Designed for exclusive ownership. Has strange copy semantics.
Can’t have a container of auto_ptrs. A standard shared-ownership smart pointers needed:
Should offer “normal” copy semantics. Hence may be stored in containers.
Many versions have been created/deployed. Typically based on reference counting.
shared_ptr Declared in <memory> A reference-counting smart pointer. Pointed-to-resources are released when the ref.count
(RC)->0.
{ shared_ptr<Widget> p1(new Widget);
shared_ptr<Widget> p2(p1);
p1->doThis(); if (p2) p2->doThat();
p2 = nullptr;… //delete is called automatically}
shared_ptr constructors Default, copy, from raw pointershared_ptr<Widget> pw1;shared_ptr<Widget> pw2(pw1);shared_ptr<Widget> pw3(new Widget); //typicalshared_ptr<Widget> pw4 = new Widget; //error
From compatible unique_ptr, auto_ptr, shared_ptr or weak_ptr.unique_ptr<Widget> makeUP();auto_ptr<Widget> makeAP();shared_ptr<Widget> pw5(makeUP());shared_ptr<Widget> pw6(makeAP());shared_ptr<const Widget> pw7(pw3);
shared_ptr Constructors From this:
It’s a raw pointer, but other shared_ptrs might already exist!
shared_ptr<ISomething> Widget::getISomething(){ return shared_ptr<ISomething>(this);}
//dangerous, could create a new ref cnt!
shared_ptr<ISomething> Widget::getISomething(){ return shared_from_this();} //Okay
Inheritance from enable_shared_from _this is required:
class Widget: public ISomething, public std::enable_shared_from_this<Widget> { … };
Some shared_ptr features
Access to underlying new pointer: Usefule for communicating with legacy APIs.
void oldAPI(Widget *pWidget);shared_ptr<Widget> spw(newWidget);oldAPI(spw.get());
Access to reference count:
if (spw.unique()) ….size_t refs = spw.use_count();
shared_ptr and incomplete types
Unlike auto_ptr (but like unique_ptr), shared_ptr supports incomplete types:class Widget; //incomplete typeauto_ptr<Widget> ap; //undefined behaviorshared_ptr<Widget> sp; //fineunique_ptr<Widget> up; //also fine
shared_ptr thus allows common coupling-reduction strategies. E.g. pimpl (private implementation)
Pimpl
The Pimpl idiom describes a way for making your header files impervious to change. You often hear advices like "Avoid change your public interface!" So you can modify your private interface, but how can you avoid recompilation when your header file defines the private methods. This is what the Pimpl does – Reduce compilation damages when your private interface changes.
Pimpl// In MyClass.h
class MyClassImp; // forward declaration of Pimpl
class MyClass { public:
MyClass (); ~MyClass(); MyClass( const MyClass &rhs ); MyClass& operator=( MyClass ); void Public_Method();
private: MyClassImp *pimpl_; // the Pimpl
};
The header defines a forward declaration of the Pimpl and other public interface. It stores a private Pimpl_ member pointer and that is all the client will ever see. There will never be any change unless you change the public interface, which you already know you shouldn't.
shared_ptr and inheritance conversions
auto_ptr fails to support some inheritance-based conversions that shared_ptr offers:
class Base {..};class Derived:public Base {..};auto_ptr<Derived> create();void use(auto_ptr<Base>);use(create()); //error
shared_ptr<Derived> create();void use(shared_ptr<Base>);use(create()); //fine
weak_ptr Weak_ptrs are like raw pointers, but they know
when they dangle: When a resource’s reference count-> 0, its weak_ptrs
expire. Shared_ptr releasing a resouce expires all weak_ptrs
shared_ptr<Widget> spw(new Widget); //RC = 1weak_ptr<Widget> wpw(spw); //RC = 1if (!wpw.expired()) … //if RC >= 1
Useful for “observing” data structures managed by others. Safer than raw pointers. Raw pointers might dangle.
weak_ptr
Also to facilitate cyclic structures that would otherwise foil RC:
ObjectA
ObjectB
RC unfriendly
shared_ptrshared_ptr
ObjectA
ObjectB
Raw pointershared_ptr
ObjectA
ObjectB
weak_ptrshared_ptr
RC friendly, safer
RC friendly, not safe
weak_ptr Weak_ptrs aren’t really smart pointers.
No deferencing operators (no -> or *) No implicit nullness test
To use weak_ptr as a pointer, create a shared_ptr from it.
weak_ptr<Widget> wpw(spw);wpw->doSomething; //won’t compile
//create a shared_ptr; throws if wpw’s expired.shared_ptr<Widget> pw1(wpw);
//pw2 is null if wpw’s expired.shared_ptr<Widget> pw2(wpw.lock());
if (pw2)pw2->doSomething();
Cost of shared_ptrs
Sample implementation 2 words in size (pointer to object, pointer to RC)
Uses dynamically allocated memory for the RC. Resource release (i.e. deletion) via a virtual function call Incurs cost for weak_ptr count even if no weak_ptrs are
used.
Shared_ptr<T>T Object
RefCountWeak count
Deleter
AllocatorOptional