What does this line/syntax mean? - c++

#include <iostream>
template<class T>
class Auto_ptr1
{
T* m_ptr;
public:
// Pass in a pointer to "own" via the constructor
Auto_ptr1(T* ptr=nullptr)
:m_ptr(ptr)
{
}
// The destructor will make sure it gets deallocated
~Auto_ptr1()
{
delete m_ptr;
}
// Overload dereference and operator-> so we can use Auto_ptr1 like m_ptr.
T& operator*() const { return *m_ptr; }
T* operator->() const { return m_ptr; }
};
// A sample class to prove the above works
class Resource
{
public:
Resource() { std::cout << "Resource acquired\n"; }
~Resource() { std::cout << "Resource destroyed\n"; }
};
int main()
{
Auto_ptr1<Resource> res(new Resource); // Note the allocation of memory here
// ... but no explicit delete needed
// Also note that the Resource in angled braces doesn't need a * symbol, since that's supplied by the template
return 0;
} // res goes out of scope here, and destroys the allocated Resource for us
I want to know what does the syntax in this line mean, I have never used it before:
Auto_ptr1<Resource> res(new Resource); // Note the allocation of memory here
I tried googling for it but there wasn't any results, and even if there were I wouldn't know how to frame the appropriate question, so I hopped on to StackOverflow for this.

Auto_ptr1 looks like a (poor) reimplementation of C++ STL's unique_ptr.
So it's a "smart-pointer" that limits the lifetime of the heap-allocated data pointed-to by m_ptr by the lifetime of the parent Auto_ptr1 instance.
Breaking it down:
Auto_ptr1<Resource> res(new Resource);
Does this:
Allocates memory for an instance of Resource using the default allocator for new (i.e. the OS-provided heap).
The address to that new Resource instance is passed into the constructor for Auto_ptr1.
Which is then stored in m_ptr inside the res value.
When res goes out-of-scope, the destructor for the Resource instance will be invoked.
I appreciate that this looks like a learning-exercise, which is fine and I encourage more people to reimplement standard library components to learn about how they work and to develop an appreciation for them - but I don't recommend using this code in production (because that's what the peer-reviewed STL and Boost libraries are for).

As #Igor Tandetnik said, it creates an instance of a class template Auto_ptr1 with type Resource called res which it initializes with a pointer to a new dynamically allocated Resource.

Related

Correct usage of unique_ptr in class member

I am trying to really move from c++98 to c++11 and newer. I have wrapped my head over most of the new stuff but I am still not sure about the correct usage of unique_ptr.
Consider the example below, where class A has a unique_ptr member (I would have used raw pointer before!). This member variable should be assigned, when user needs, by calling a function somewhere else (not part of the class). Is this the correct usage? If not, what is the best alternative?
class A {
private:
unique_ptr<MyType> mt;
public:
void initStuff() {
mt.reset(std::move(StaticFuncSomewhereElese::generateMyType()));
}
};
MyType* StaticFuncSomewhereElese::generateMyType() {
MyType* temp = new MyType(...);
//do stuff to temp (read file or something...)
return temp;
}
Your code works fine (although the redundant* move can be omitted) but it would be better to construct the unique_ptr as early as possible:
class A {
private:
std::unique_ptr<MyType> mt;
public:
void initStuff() {
mt = StaticFuncSomewhereElese::generateMyType();
}
};
std::unique_ptr<MyType> StaticFuncSomewhereElese::generateMyType() {
auto temp = std::make_unique<MyType>(…);
// `make_unique` is C++14 (although trivially implementable in C++11).
// Here's an alternative without `make_unique`:
// std::unique_ptr<MyType> temp(new MyType(…));
//do stuff to temp (read file or something...)
return temp;
}
This way it is clear that the return value of generateMyType must be deleted by the caller, and there's less possibility for memory leaks (e.g. if generateMyType returns early).
* The move is redundant because:
Raw pointers can't be moved.
The result of the generateMyType() expression is already an rvalue anyways.
Is this the correct usage?
Besides std::move being redundant, yes this is correct. It is redundant because a) Bare pointers are copied, whether they are lvalues or rvalues and b) The function doesn't return a reference, so the return value is already an rvalue so there is no need to convert.
But there is room for improvement. In particular, I recommend to return a unique pointer from the factory function:
std::unique_ptr<MyType> StaticFuncSomewhereElese::generateMyType()
This prevents temp from leaking if the initialization throws an exception, and makes it much harder for the user of the factory to accidentally leak the returned pointer.
Why not make it a generic template factory?
In header.
template <typename T>
std::unique_ptr<T> generateMyType();
classss A {
private:
std::unique_ptr<MyType> mt;
std::unique_ptr<MyOtherType> mot;
public:
void initStuff() {
mt = generateMyType<MyType>();
mot = generateMyType<MyOtherType>();
}
};
And in the source file
template <typename T>
std::unique_ptr<T> generateMyType()
{
auto temp = std::make_unique<T>();
return temp;
}

Is pairing weak_ptr to unique_ptr a good idea?

I know it sound absurd to use weak_ptrs with unique_ptrs, but bear with me please.
I have a set of widgets and animations that act on them. The widgets have a clear owner, who creates and destroys them. All the widgets are created, destroyed, animated in one thread, so one widget can't be destroyed while the animation code is running. As you can see, the widgets are are somehow shared with the animations, but the animation should stop if the widgets gets deleted.
The current approach is to use std::unique_ptr for the owners of the widgets and expose them as raw pointers to the animations. This makes very difficult finding/debugging dangling pointers. One proposal was to change to std::shared_ptr inside the owner class and expose std::weak_ptrs to the animations, but this will add some unwanted/unneeded overhead in the system.
Is it possible (a good idea?) to create some sort of weak_ptr on top of std::unique_ptr that just flags that the pointer was deleted? If yes, can you please suggest me some implementations with minimal overhead for single threaded usage.
EDIT:
One more clarification - the widgets are used in one thread, but the application has multiple threads. Also lots of animations run in parallel and each animation is updated 60 times/second. The overhead from std::shared_ptr/std::weak_ptr comes from the (atomic) counter used inside std::shared_ptr, that actually is not needed in this particular case.
EDIT:
I'm not asking if I can use std::weak_ptr with std::unique_ptr, I know this is not possible. I'm asking if it is a good idea/possible to build something with similar behavior as std::weak_ptr that can be paired with std::unique_ptr
No, you can't use std::weak_ptr with std::unique_ptr. You make it a std::shared_ptr and expose a std::weak_ptr, just like you said.
As far as the overhead of reference counting is concerned, I highly doubt that will be the bottleneck of your application, so profile and worry about that only when it becomes (probably never) so.
Sure, it's a reasonable idea. It provides control over the lifetime of the object while giving the subordinate threads the opportunity of detecting its disappearance.
Of course the lock() method of your weak objects will need to return something that does not itself allow re-sharing.
You can do this by encapsulating existing shared_ptr and weak_ptr objects.
A simple example:
#include <iostream>
#include <memory>
// some type we're going to use for testing
struct Foo {
~Foo() {
std::cout << "Foo destroyed" << std::endl;
}
void use() const {
std::cout << "using Foo" << std::endl;
}
};
// forward declaration
template<class T> struct weak_object_ptr;
// a pointer that keeps the object alive but is not itself copyable
template<class T>
struct keep_alive_ptr
{
// make it moveable
keep_alive_ptr(keep_alive_ptr&&) = default;
keep_alive_ptr& operator=(keep_alive_ptr&&) = default;
// provide accessors
T& operator*() const {
return *_ptr;
}
T* operator->() const {
return _ptr.get();
}
private:
// private constructor - the only way to make one of these is to lock a weak_object_ptr
keep_alive_ptr(std::shared_ptr<T> ptr)
: _ptr { std::move(ptr) }
{}
// non-copyable
keep_alive_ptr(const keep_alive_ptr&) = delete;
keep_alive_ptr& operator=(const keep_alive_ptr&) = delete;
friend weak_object_ptr<T>;
std::shared_ptr<T> _ptr;
};
// a weak reference to our shared object with single point of ownership
template<class T>
struct weak_object_ptr
{
weak_object_ptr(std::weak_ptr<T> w)
: _weak { std::move(w) }
{}
keep_alive_ptr<T> lock() const {
return keep_alive_ptr<T> { _weak.lock() };
}
private:
std::weak_ptr<T> _weak;
};
// a shared object store and lifetime controller
template<class T>
struct object_controller
{
// helpful universal constructor
template<class...Args>
object_controller(Args&&...args)
: _controller { std::make_shared<T>(std::forward<Args>(args)...) }
{}
weak_object_ptr<T> get_weak() const {
return weak_object_ptr<T> { _controller };
}
void reset() {
_controller.reset();
}
private:
std::shared_ptr<T> _controller;
};
// test
using namespace std;
int main(){
auto foo_controller = object_controller<Foo> {};
auto weak1 = foo_controller.get_weak();
auto weak2 = foo_controller.get_weak();
{
auto strong1 = weak1.lock();
strong1->use();
cout << "trying to destroy Foo\n";
foo_controller.reset();
auto strong2 = weak2.lock();
strong2->use();
cout << "strong2 going out of scope\n";
}
return 0;
}
expected output (note that the destruction of Foo takes place as early as it is legally allowed):
using Foo
trying to destroy Foo
using Foo
strong2 going out of scope
Foo destroyed

Managing C type lifecycle using boost's shared_ptr?

I have a question similar to How to manage object life time using Boost library smart pointers? but, in my case, the "object" isn't a C++ object at all, but an opaque type returned/passed out from a C API. The type does not have pointer semantics, i.e., there is no dereferencing; it is, however, passed as an argument to other functions in the C API. The type also has a definitive close API which must be called in order to clean up internal resources.
So, I have a C API that's something along the lines of
opaque_legacy_type_t x;
XXopen(..., &x); // allocates/opens resource and fills out 'x' to be used later
XXdoSomethingWithResource(x, ...); // do something with resources related to 'x'
...more actions...
XXclose(x); // closes and cleans up resources related to 'x'
For various reasons, in my C++ code I would like to manage "instances" of opaque_legacy_type_t much like I would manage heap-allocated object instances, i.e. with similar sharing semantics as boost::shared_ptr<>. It seems that shared_ptr offers enough that I can manage calling XXclose by doing this:
opaque_legacy_type_t x;
XXopen(..., &x);
boost::shared_ptr<opaque_legacy_type_t> managed(x, XXclose);
But, since opaque_legacy_type_t doesn't have pointer semantics, the usage of managed is a bit clumsy.
What I'd like to do is have something like a managed_type that is similar to shared_ptr, and am looking for ideas that don't require me to write it all.
EDIT: I corrected my original screw-up in the example. The legacy API takes the opaque type by value rather than by pointer.
Since all of the legacy API take a pointer to the opaque type, you could use shared pointers directly. The key is for you to not declare the original structure on the stack, but rather allocate it via new:
int main () {
std::shared_ptr<opaque_legacy_type_t> x(new opaque_legacy_type_t,
[](opaqeue_legacy_type_t* p) { XXClose(p); delete p; });
XXopen(..., x.get());
XXdoSomethingWithResource(x.get(), ...);
}
EDIT: If some API take the opaque type by value instead of pointer, then pass the dereferenced pointer.
int main () {
std::shared_ptr<opaque_legacy_type_t> x(new opaque_legacy_type_t,
[](opaqeue_legacy_type_t* p) { XXClose(*p); delete p; });
XXopen(..., x.get());
XXdoSomethingWithResource(*x, ...);
}
You could use boost smart pointers together with the pimpl idom:
class shared_opaque_legacy_type_t {
struct impl {
opaque_legacy_type_t t;
impl(...) { XXOpen(..., t); }
~impl(...) { XXClose(t); }
}
boost::shared_ptr<impl> _impl;
public:
shared_opaque_lagacy_type_t(...) : _impl(new impl(...)) {}
opaque_legacy_type_t* get() {
return _impl->t;
}
};
shared_opaque_legacy_type_t x(...);
XXdoSomethingWithResource(x.get(), ...);
The drawback is that you could still call XXclose(x.get()) and invalidate your object.
UPDATE: Fixed it. :-)
You could write a wrapper to use with boost that will call the open() in the ctor and the close() in the dtor.
I voted for Rob's answer that just uses a shared_ptr with no wrapper, but if you really want to avoid dynamic allocation here's a simple little example of how to do that.
It's a template that directly holds the handle and does no allocation. You pass the constructor a functor that creates an object of the opaque type, and a deleter to call when the type needs to be destroyed. It's movable and non-copyable so now shared reference count is needed. It implements implicit conversion operators so you can use it where you'd use a value of the held type.
template<typename T,typename D>
class opaque_type_handle {
T handle;
D deleter;
bool needs_delete;
public:
template<typename F>
opaque_type_handle(F f,D d) : handle(f()), deleter(d), needs_delete(true) {}
opaque_type_handle(opaque_type_handle const &) = delete;
opaque_type_handle &operator=(opaque_type_handle const &) = delete;
opaque_type_handle(opaque_type_handle &&rhs) : handle(rhs.handle),deleter(rhs.deleter),needs_delete(true) {
rhs.needs_delete = false;
}
opaque_type_handle &operator=(opaque_type_handle &&rhs) {
handle = rhs.handle;
deleter = rhs.deleter;
needs_delete = true;
rhs.needs_delete = false;
returh *this;
}
~opaque_type_handle() {
if(needs_delete) {
deleter(handle);
}
}
operator T&() { return handle; }
operator T() const { return handle; }
};
Use it like so:
// wrap up the code for creating an opaque_legacy_type_t handle
typedef opaque_type_handle<opaque_legacy_type_t,decltype(&XXclose)> legacy_handle;
legacy_handle make_legacy_handle(...) {
return legacy_handle(
[](){
opaque_legacy_type_t tmp;
XXopen(..., &tmp);
return tmp;
},
&XXclose
);
}
legacy_handle x = make_legacy_handle(...);
XXdoSomethingWithResource(x,...);

Is there a potential for resource leak/double free here?

The following sample (not compiled so I won't vouch for syntax) pulls two resources from resource pools (not allocated with new), then "binds" them together with MyClass for the duration of a certain transaction.
The transaction, implemented here by myFunc, attempts to protect against leakage of these resources by tracking their "ownership". The local resource pointers are cleared when its obvious that instantiation of MyClass was successful. The local catch, as well as the destructor ~MyClass return the resources to their pool (double-frees are protected by teh above mentioned clearing of the local pointers).
Instantiation of MyClass can fail and result in an exception at two steps (1) actual memory allocation, or (2) at the constructor body itself. I do not have a problem with #1, but in the case of #2, if the exception is thrown AFTER m_resA & m_resB were set. Causing both the ~MyClass and the cleanup code of myFunc to assume responsibility for returning these resources to their pools.
Is this a reasonable concern?
Options I have considered, but didn't like:
Smart pointers (like boost's shared_ptr). I didn't see how to apply to a resource pool (aside for wrapping in yet another instance).
Allowing double-free to occur at this level but protecting at the resource pools.
Trying to use the exception type - trying to deduce that if bad_alloc was caught that MyClass did not take ownership. This will require a try-catch in the constructor to make sure that any allocation failures in ABC() ...more code here... wont be confused with failures to allocate MyClass.
Is there a clean, simple solution that I have overlooked?
class SomeExtResourceA;
class SomeExtResourceB;
class MyClass {
private:
// These resources come out of a resource pool not allocated with "new" for each use by MyClass
SomeResourceA* m_resA;
SomeResourceB* m_resB;
public:
MyClass(SomeResourceA* resA, SomeResourceB* resB):
m_resA(resA), m_resB(resB)
{
ABC(); // ... more code here, could throw exceptions
}
~MyClass(){
if(m_resA){
m_resA->Release();
}
if(m_resB){
m_resB->Release();
}
}
};
void myFunc(void)
{
SomeResourceA* resA = NULL;
SomeResourceB* resB = NULL;
MyClass* pMyInst = NULL;
try {
resA = g_pPoolA->Allocate();
resB = g_pPoolB->Allocate();
pMyInst = new MyClass(resA,resB);
resA=NULL; // ''ownership succesfully transfered to pMyInst
resB=NULL; // ''ownership succesfully transfered to pMyInst
// Do some work with pMyInst;
...;
delete pMyInst;
} catch (...) {
// cleanup
// need to check if resA, or resB were allocated prior
// to construction of pMyInst.
if(resA) resA->Release();
if(resB) resB->Release();
delete pMyInst;
throw; // rethrow caught exception
}
}
Here is your chance for a double call to release:
void func()
{
MyClass a(resourceA, resourceB);
MyClass b(a);
}
Whoops.
If you use an RIAA wrapper fro your resources you will be much less likely to make mistakes. Doing it this way is error prone. You are currently missing the copy constructor and assignment operator on MyClass that could potentially lead to a double call to Release() as shown above.
Because of the complexity of handling resource a class should only own one resource. If you have multiple resource delegate their ownership to a class that it dedicated to their ownership and use multiple of these objects in your class.
Edit 1
Lut us make some assumptions:
Resources are shared and counted. You increment the count with Acquire() and decrement the count with Release(). When count reaches zero they are automatically destroyed.
class ReferenceRapper
{
ReferenceBase* ref;
public:
ReferenceWrapper(ReferenceBase* r) : ref (r) {/* Pool set the initial count to 1 */ }
~ReferenceWrapper() { if (ref) { ref->Release();} }
/*
* Copy constructor provides strong exception guarantee (aka transactional guarantee)
* Either the copy works or both objects remain unchanged.
*
* As the assignment operator is implemented using copy/swap it also provides
* the strong exception guarantee.
*/
ReferenceWrapper(ReferenceWrapper& copy)
{
if (copy.ref) {copy.ref->Acquire();}
try
{
if (ref) {ref->Release();}
}
catch(...)
{
if (copy.ref)
{ copy.ref->Release(); // old->Release() threw an exception.
// Must reset copy back to its original state.
}
throw;
}
ref = copy.ref;
}
/*
* Note using the copy and swap idium.
* Note: To enable NRVO optimization we pass by value to make a copy of the RHS.
* rather than doing a manual copy inside the method.
*/
ReferenceWrapper& operator(ReferenceWrapper rhsCopy)
{
this->swap(rhsCopy);
}
void swap(ReferenceWrapper& rhs) throws ()
{
std::swap(ref, rhs.ref);
}
// Add appropriate access methods like operator->()
};
Now that the hard work has been done (managing resources). The real code becomes trivial to write.
class MyClass
{
ReferenceWrapper<SomeResourceA> m_resA;
ReferenceWrapper<SomeResourceB> m_resB;
public:
MyClass(ReferenceWrapper<SomeResourceA>& a, ReferenceWrapper<SomeResourceB>& b)
: m_resA(a)
, m_resB(b)
{
ABC();
}
};
void myFunc(void)
{
ReferenceWrapper<SomeResourceA> resA(g_pPoolA->Allocate());
ReferenceWrapper<SomeResourceB> resB(g_pPoolB->Allocate());
std::auto_ptr<MyClass> pMyInst = new MyClass(resA, resB);
// Do some work with pMyInst;
}
Edit 2 Based on comment below that resources only have one owner:
If we assume a resource has only one owner and is not shared then it becomes trivial:
Drop the Release() method and do all the work in the destructor.
Change the Pool methods so that the construct the pointer into a std::auto_ptr and return the std::auto_ptr.
Code:
class MyClass
{
std::auto_ptr<SomeResourceA> m_resA;
std::auto_ptr<SomeResourceB> m_resB;
public:
MyClass(std::auto_ptr<SomeResourceA>& a, std::auto_ptr<SomeResourceB>& b)
: m_resA(a)
, m_resB(b)
{
ABC();
}
};
void myFunc(void)
{
std::auto_ptr<SomeResourceA> resA(g_pPoolA->Allocate());
std::auto_ptr<SomeResourceB> resB(g_pPoolB->Allocate());
std::auto_ptr<MyClass> pMyInst = new MyClass(resA, resB);
// Do some work with pMyInst;
}
I don't see any leak in this small code.
If the constructor throws exception, then the destructor would not be called, since the object never existed. Hence I don't see double-delete either!
From this article by Herb Sutter :Constructor Exceptions in C++, C#, and Java:
constructor conceptually turns a
suitably sized chunk of raw memory
into an object that obeys its
invariants. An object’s lifetime
doesn’t begin until its constructor
completes successfully. If a
constructor ends by throwing an
exception, that means it never
finished creating the object and
setting up its invariants — and at
the point the exceptional constructor
exits, the object not only doesn’t
exist, but never existed.
A destructor/disposer conceptually
turns an object back into raw memory.
Therefore, just like all other
nonprivate methods,
destructors/disposers assume as a
precondition that “this” object is
actually a valid object and that its
invariants hold. Hence,
destructors/disposers only run on
successfully constructed objects.
I think this should clear your doubts!
Your code is fine. But to make it even better, use some kind of smart-pointer!
Edit: for example you can use shared_ptr:
class SomeExtResourceA;
class SomeExtResourceB;
class MyClass {
private:
// These resources come out of a resource pool not allocated with "new" for each use by MyClass
shared_ptr<SomeResourceA> m_resA;
shared_ptr<SomeResourceB> m_resB;
public:
MyClass(const shared_ptr<SomeResourceA> &resA, const shared_ptr<SomeResourceB> &resB):
m_resA(resA), m_resB(resB)
{
ABC(); // ... more code here, could throw exceptions
}
}
};
void myFunc(void)
{
shared_ptr<SomeResourceA> resA(g_pPoolA->Allocate(), bind(&SomeResourceA::Release, _1));
shared_ptr<SomeResourceB> resB(g_pPoolB->Allocate(), bind(&SomeResourceB::Release, _1));
MyClass pMyInst(resA,resB);
// you can reset them here if you want, but it's not necessery:
resA.reset(), resB.reset();
// use pMyInst
}
I find this solution with RAII much simpler.
Just put if (pMyInst) { ... } around release/delete code in your catch and you are fine.
The classic usage to explicitly take ownership is the std::auto_ptr
Something like this:
std::auto_ptr<SomeResourceA>(g_pPoolA->Allocate()) resA;
std::auto_ptr<SomeResourceB>(g_pPoolB->Allocate()) resB;
pMyInst = new MyClass(resA.release(),resB.release());
You transfer the ownership when you call the constructor.

Implementing Smart Pointer - Dynamic Allocation with templates

I'm in the process of writing a smart pointer countedptr and I've hit a speed bump. The basic function of countedptr is to work like any other smart pointer and also have a count of how many pointers are pointing to a single object. So far, the code is:
[SOLVED]
#include "std_lib_facilities.h"
template <class T>
class counted_ptr{
private:
T* pointer;
int* count;
public:
counted_ptr(T* p = 0, int* c = new int(1)) : pointer(p), count(c) {} // default constructor
explicit counted_ptr(const counted_ptr& p) : pointer(p.pointer), count(p.count) { ++*count; } // copy constructor
~counted_ptr() { --*count; delete pointer; }
counted_ptr& operator=(const counted_ptr& p)
{
pointer = p.pointer;
count = p.count;
++*count;
return *this;
}
T* operator->() const{ return pointer; }
T& operator*() const { return *pointer; }
int Get_count() const { return *count; }
};
int main()
{
counted_ptr<double> one;
counted_ptr<double>two(one);
int a = one.Get_count();
cout << a << endl;
}
When I try to do something like
one->pointer = new double(5);
then I get a compiler error saying "request for member 'pointer' in '*(&one)->counted_ptr::operator->with T = double' which is of non-class type double".
I considered making a function to do this, and while I could make a function to allocate an array of T's, I can't think of a way of making one for allocating actual objects. Any help is appreciated, thanks.
Old Solution
What about another assignment operator?
counted_ptr& counted_ptr::operator=(T* p)
{
if (! --*count) { delete count; }
pointer = p;
count = new int(1);
return *this;
}
...
one = new double(5);
Also, your destructor always deletes a shared pointer, which is probably what caused *one to be a random nomber. Perhaps you want something like:
counted_ptr::~counted_ptr() { if (! --*count) { delete pointer; delete count; } }
New Solution
As you want repointing a counted_ptr (eg one = new double(5)) to update all related counted_ptrs, place both the pointer and the count in a helper class, and have your pointer class hold a pointer to the helper class (you might already be headed down this path). You could go two ways in filling out this design:
Make the helper class a simple struct (and a private inner class) and place all the logic in the outer class methods
Make counted_ptr the helper class. counted_ptr maintains a reference count but doesn't automatically update the count; it's not a smart pointer, it only responds to release and retain messages. If you're at all familiar with Objective-C, this is basically its traditional memory management (autoreleasing aside). counted_ptr may or may not delete itself when the reference count reaches 0 (another potential difference from Obj-C). counted_ptrs shouldn't be copyable. The intent is that for any plain pointer, there should be at most one counted_ptr.
Create a smart_ptr class that has a pointer to a counted_ptr, which is shared among smart_ptr instances that are supposed to hold the same plain pointer. smart_ptr is responsible for automatically updating the count by sending its counted_ptr release and retain methods.
counted_ptr may or may not be a private inner class of shared_ptr.
Here's an interface for option two. Since you're doing this as an exercise, I'll let you fill out the method definitions. Potential implementations would be similar to what's already been posted except that you don't need a copy constructor and copy assignment operator for counted_ptr, counted_ptr::~counted_ptr doesn't call counted_ptr::release (that's smart_ptr::~smart_ptr's job) and counted_ptr::release might not free counted_ptr::_pointer (you might leave that up to the destructor).
// counted_ptr owns its pointer an will free it when appropriate.
template <typename T>
class counted_ptr {
private:
T *_pointer;
size_t _count;
// Make copying illegal
explicit counted_ptr(const counted_ptr&);
counted_ptr& operator=(const counted_ptr<T>& p);
public:
counted_ptr(T* p=0, size_t c=1);
~counted_ptr();
void retain(); // increase reference count.
bool release(); // decrease reference count. Return true iff count is 0
void reassign(T *p); // point to something else.
size_t count() const;
counted_ptr& operator=(T* p);
T& operator*() const;
T* operator->() const;
};
template <typename T>
class smart_ptr {
private:
counted_ptr<T> *_shared;
void release(); // release the shared pointer
void retain(); // retain the shared pointer
public:
smart_ptr(T* p=0, int c=1); // make a smart_ptr that points to p
explicit smart_ptr(counted_ptr<T>& p); // make a smart_ptr that shares p
explicit smart_ptr(smart_ptr& p); // copy constructor
~smart_ptr();
// note: a smart_ptr's brethren are the smart_ptrs that share a counted_ptr.
smart_ptr& operator=(smart_ptr& p); /* Join p's brethren. Doesn't alter pre-call
* brethren. p is non-const because this->_shared can't be const. */
smart_ptr& operator=(counted_ptr<T>& p); /* Share p. Doesn't alter brethren.
* p is non-const because *this isn't const. */
smart_ptr& operator=(T* p); // repoint this pointer. Alters brethren
size_t count() const; // reference count
T& operator*() const; // delegate these to _shared
T* operator->() const;
};
Hopefully, the only ambiguous points above are the intentional ones.
(Sorry, newbie here, and can't leave comments). What Adatapost added, "one=new double(5);" should work. One other change needed, though: the reference counting needs a little help.
...
~counted_ptr() {
--*count;
// deallocate objects whose last reference is gone.
if (!*count)
{
delete pointer;
delete count;
}
}
counted_ptr& operator=(const counted_ptr& p)
{
// be careful to accommodate self assignment
++*p.count;
// may lose a reference here
--*count;
if (!*count)
{
delete pointer;
delete count;
}
count=p.count;
pointer=p.pointer;
return *this;
}
Of course, there's some code repetition here. It might make sense to refactor that code into its own function, e.g.
private:
/** remove our reference */
void release()
{
--*count;
if (!*count)
{
delete pointer;
delete count;
}
}
Did you, perhaps, mean "one.pointer=new double(5);"? Writing "one->pointer=new double(5);" invokes counted_ptr<double>::operator->. That is, it is approximately equivalent to:
double *tmp = one.operator->(); // returns one.pointer
tmp->pointer = new double(5);
But a double pointer isn't a structure, and so it doesn't have a pointer member.
Since the immediate problem has already been solved, I want to offer something more long term:
As you continue to develop this code, you'll definitely want to offer it up for full review by experienced programmers, whether here or elsewhere. There were a few obvious problems with your code as you posted it, though outis has helped correct them. But even once your code all compiles and seems to work in your own tests, there may be tests and situations which you haven't yet learned to think about. Smart pointers can easily have subtle problems that don't show up until very specific situations. So you'll want others to look over your code to find anything which you may have missed.
Please don't take this as any kind of insult towards your current code. I'm just offering this as friendly advice to ensure you learn the most you can out of this project.
Unless you are not doing this for academic reasons, you might want to use consider using the use_count() member of boost::shared_ptr. It's not entirely efficient, but it does work and you're better off using something well tested, mature, and thread safe. If you are doing this for learning purposes, be sure to check out the treatment of Reference Counting and Smart Pointers in More Effective C++.
You need to decrement the count and possibly delete the pointer to the old value in operator = before you overwrite it. You also need 'delete count' everywhere you have 'delete pointer' to avoid leaking memory