template method question

G

Gonçalo Rodrigues

Hi all,

The following (test) program is not working as I expected.

Note: The code is a bit long but is easy to understand: There is a
class Object implementing ref counting. A Ref<T> template (with a full
Ref<Object> specialization) that works like a smart pointer to the
Object-rooted hierarchy. The only way to create Object instances is
via a static factory that returns a Ref<Object> to a heap allocated
object.

#include <iostream>

//Macros.
#ifndef NULL
#define NULL 0
#endif

//Templates.
template<typename T>
class Ref {
public:
//Constructors.
explicit Ref(T* ptr) {
if (NULL == ptr) {
throw "NULL pointer.";
};
this->ptr = ptr;
ptr->incCount();
};

Ref(const Ref& ref) : ptr(ref.getPtr()) {
this->ptr->incCount();
};

//Destructor.
~Ref() {
this->ptr->decCount();
if (0 == this->ptr->getCount()) {
delete this->ptr;
};
this->ptr = NULL;
};

//Descriptors.
T* getPtr() const {
return this->ptr;
};

//Operator protocol.
T& operator*() const {
return *(this->ptr);
}

T* operator->() const {
return this->ptr;
};

private:
T* ptr;
};

//Forward declaration.
class Object;

//Full specialization.
template<>
class Ref<Object> {
public:
//Constructors.
explicit Ref(Object* ptr) {
if (NULL == ptr) {
throw "NULL pointer.";
};
this->ptr = ptr;
ptr->incCount();
};

Ref(const Ref& ref) : ptr(ref.getPtr()) {
this->ptr->incCount();
};

//Destructor.
~Ref() {
this->ptr->decCount();
if (0 == this->ptr->getCount()) {
delete this->ptr;
};
this->ptr = NULL;
};

//Descriptors.
Object* getPtr() const {
return this->ptr;
};

//Operator protocol.
Object& operator*() const {
return *(this->ptr);
}

Object* operator->() const {
return this->ptr;
};

private:
Object* ptr;
};

class Object {
public:
static Ref<Object> create() {
return Ref<Object>(new Object);
};

virtual ~Object() {};

//Reference count helpers.
long getCount() {
return this->count;
};

void incCount() {
this->count++;
};

void decCount() {
this->count--;
};

protected:
//Protect constructors.
Object() : count(0) {};

private:
long count;

//Disallow.
Object(const Object& obj);
Object& operator=(const Object& rhs);
};

int main() {
Ref<Object> ref = Object::create();
std::cout << "Object count: " << ref->getCount() << std::endl;
std::cout << "Object pointer: " << (long)ref.getPtr() <<
std::endl;
Ref<Object> ref1(ref);
std::cout << "Object count: " << ref1->getCount() <<
std::endl;
std::cout << "Object pointer: " << (long)ref1.getPtr() <<
std::endl;
};

Compiling and running is fine and dandy. I get:

Object count: 1
Object pointer: 3082872
Object count: 2
Object pointer: 3082872

But once I replace the copy-constructor in the full specialization
Ref<Object> by the template method

template<typename U>
Ref(const Ref<U>& ref) : ptr(ref.getPtr()) { //Upcast here.
this->ptr->incCount();
};

I get the output

Object count: 1
Object pointer: 3082872
Object count: 1
Object pointer: 3082872

The reference counter is not being updated - although the pointer is
getting assigned. Anyone knows what is wrong with the above template
method? Any ideas?

TIA, best regards,
G. Rodrigues
 
R

Rob Williscroft

Gonçalo Rodrigues wrote in in comp.lang.c++:
But once I replace the copy-constructor in the full specialization
Ref<Object> by the template method

template<typename U>
Ref(const Ref<U>& ref) : ptr(ref.getPtr()) { //Upcast here.
this->ptr->incCount();
};

Its called a converting constructor and it doesn't implement
the copy constructor, when the compiler need to copy it will
use the implicitly generated (memberwise) copy constructor.

Leave the copy constructor in place and *add* this converting
constructor.

Rob.
 
G

Gonçalo Rodrigues

Gonçalo Rodrigues wrote in in comp.lang.c++:


Its called a converting constructor and it doesn't implement
the copy constructor, when the compiler need to copy it will
use the implicitly generated (memberwise) copy constructor.

Ahhh... understood.
Leave the copy constructor in place and *add* this converting
constructor.

Thanks, adding the template method (instead of replacing) does make
the output right.

Another question: I'd assume that, since if not implemented the
compiler also synthesizes an operator assignment for you, then I have
to do the same thing, that is, implement an assignment operator then
add the template method operator=, right?

TIA, With my best regards,
G. Rodrigues
 
R

Rob Williscroft

Gonçalo Rodrigues wrote in in comp.lang.c++:
Thanks, adding the template method (instead of replacing) does make
the output right.

Another question: I'd assume that, since if not implemented the
compiler also synthesizes an operator assignment for you, then I have
to do the same thing, that is, implement an assignment operator then
add the template method operator=, right?

Yep.

Rob.
 
V

velthuijsen

I've looked through the code that the OP gave.
I believe this is about a post of mine - but I am guessing here, you
should keep the quotes.

My answer: no you haven't missed nothing. I've pushed the
specialization code in Ref<Object> to the general template Ref<T> and
deleted the (full) specialization.

Thank you.
It was (at least for me) not a wasted effort. I Learned a bit more
about how to work with templates from it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,149
Latest member
Vinay Kumar Nevatia0
Top