473,387 Members | 1,834 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Fully Answered Interview questions

Fully answered interview questions in c and c++ from
http://www.faiqs.com

Nov 27 '06 #1
25 2732
Syam wrote:
Fully answered interview questions in c and c++ from
http://www.faiqs.com
The answers (at least for the first few questions) are in correct.
They aren't the questions I would ask during an interview anyhow.

For instannce question #1
What is the output of printf(“%d”)
?

1. %d helps to read integer data type of a given variable
2. when we write (“%d”, X) compiler will print the value of x
assumed in the main
3. but nothing after (“%d”) so the output will be garbage
4. printf is an overload function doesnt check consistency of the
arg list – segmentation fault
#1 Printf reads NOTHING.
#2 "x assumed in main" is wrong, first, C++ is case dependent. Second,
what X gets printed depends what is defined in the calling scope. Even
if the printf is called form main(), the X may be declared elsewhere.

#3 is likely but not the correct answer.
#4 is beginning to sound correct, but printf is NOT "an overload
functino".

The correct answer is:

1. Printf does not (can not) check the consistency of the arguments.
You must pass the correct number and type arguments to match the
format string.

2. Failure to do so yields undefined behavior (printing garbage and
segmentation faults are just part of the unbounded possibilities
here).

Nov 27 '06 #2
(ok, let's try again. I didn't see this was comp.lang.c++.moderated. If
this ends up posting twice, it's because several minutes later this
response has still not appeared)
Syam wrote:
Fully answered interview questions in c and c++ from
http://www.faiqs.com
Many of those answers are inaccurate or they do not answer the
question.

1. What is the output of printf( "%d" );

The correct answer is given by Ron Natalie: as the function will look
for another argument that doesn't exist, it will cause undefined
behaviour. It might output a random number or it might crash (seg
fault). Unlikely to do anything other than these two though technically
it could.

2. What will happen if I say "delete this" ?

The answer given is a load of nonsense. Some of the statements are
plain false, others simply divert and do not answer the question.

Anyway, it should cause the object to be destructed as though you had
called delete on the pointer from outside. For it to work correctly the
following must be the case:

- The object must have been created with new. That is, regular new.
new(nothrow) would also work but no placement new, no new[].

- If this is a base class and the real object is derived from this, the
destructor must be virtual.

3. Difference between C structure and C++ structure.

Well I will assume they mean C struct and C++ struct as struct is the
keyword not structure. The question does not ask the difference between
a C++ class and a C++ struct.

The real answer is that a C++ struct is effectively a C++ class with
default public access and inheritance. Unlike a C struct you can have
member functions, have private members if you want and have it derive
from base classes (as well as derive classes from it).

There is also a difference in the notation for using one, i.e. you can
simply refer to it by its type without a "struct" prefix or a typedef.

This answer is false:
"members of a struct in C are by default public, in C++ private". It is
false not because C doesn't have a concept of private because
technically it's true, they are by default public even if it is
impossible to change it. But in C++ they are also by default public,
therefore the statement is false.

This answer is off-topic:
"unions like structs except they shaer memory ..." (goes on to give
details on unions).;

4. Difference between assignment operator and copy constructor.

None of the given answers are complete and accurate. This is close.
"copy constructor creates a new object, assignment operator has to deal
with existing data in the object" .

Better answer is "copy constructor creates a new object that clones the
existing one, assignment modifies an existing object to be the clone of
another one". You might add that "although one may overload the copy
constructor and assignment such that the two objects do not actually
match, doing so would be unusual and would be against the normal nature
of what these are supposed to do".

This answer is not quite correct:

"copy constructor always creates a new object, assignment never does".
Because assignment can, it will often create a temporary object to be
exception safe should this action fail.

5. Difference between overloading and overriding.
Let me say this is a horrible question because it is based on one
knowing the technical names for things.

Anyway, overloading is using the same name but a different parameter
list. Overriding uses the same parameter list but where the original
function has been declared virtual in a base class. Overloads are
resolved at compile time, overrides usually at run-time. Overloads can
be particularly useful where one set of code could call either version
according to different circumstances, for example, a template
parameter.

6. Virtual
7. Dynamic binding.

Neither of these are questions. Or does it mean "what are they" in
which case they may as well be asked together, or ask "what is
polymorphism" and perhaps could have been combined with the above
question.

Anyway, the principle is to allow code to call a method by what it does
rather than how it does it, with the actual function that gets called
to be resolved at run-time. The same code that holds a pointer or
reference to a base class could invoke different overloads at different
times, depending on what actual object it has and the type of that
object.

8. Explain the need for a virtual destructor:

The 2nd and 3rd and 5th answers pretty much answer this.

9. Rule of 3.

The first answer answers it best, although the term "user-defined" was
never actually used, but was probably implied. Generally though if it
needs any of the 3 it needs the other two as well.

10. Why do you need a virtual destructor when someone says delete using
a Base ptr thats pointing @ a derived object?

Because the standard says you do.

Nov 27 '06 #3

Syam wrote:
Fully answered interview questions in c and c++ from
http://www.faiqs.com
Many of those answers are inaccurate or they do not answer the
question.

1. What is the output of printf( "%d" );

The correct answer is given by Ron Natalie: as the function will look
for another argument that doesn't exist, it will cause undefined
behaviour. It might output a random number or it might crash (seg
fault). Unlikely to do anything other than these two though technically
it could.

2. What will happen if I say "delete this" ?

The answer given is a load of nonsense. Some of the statements are
plain false, others simply divert and do not answer the question.

Anyway, it should cause the object to be destructed as though you had
called delete on the pointer from outside. For it to work correctly the
following must be the case:

- The object must have been created with new. That is, regular new.
new(nothrow) would also work but no placement new, no new[].

- If this is a base class and the real object is derived from this, the
destructor must be virtual.

3. Difference between C structure and C++ structure.

Well I will assume they mean C struct and C++ struct as struct is the
keyword not structure. The question does not ask the difference between
a C++ class and a C++ struct.

The real answer is that a C++ struct is effectively a C++ class with
default public access and inheritance. Unlike a C struct you can have
member functions, have private members if you want and have it derive
from base classes (as well as derive classes from it).

There is also a difference in the notation for using one, i.e. you can
simply refer to it by its type without a "struct" prefix or a typedef.

This answer is false:
"members of a struct in C are by default public, in C++ private". It is
false not because C doesn't have a concept of private because
technically it's true, they are by default public even if it is
impossible to change it. But in C++ they are also by default public,
therefore the statement is false.

This answer is off-topic:
"unions like structs except they shaer memory ..." (goes on to give
details on unions).;

4. Difference between assignment operator and copy constructor.

None of the given answers are complete and accurate. This is close.
"copy constructor creates a new object, assignment operator has to deal
with existing data in the object" .

Better answer is "copy constructor creates a new object that clones the
existing one, assignment modifies an existing object to be the clone of
another one". You might add that "although one may overload the copy
constructor and assignment such that the two objects do not actually
match, doing so would be unusual and would be against the normal nature
of what these are supposed to do".

This answer is not quite correct:

"copy constructor always creates a new object, assignment never does".
Because assignment can, it will often create a temporary object to be
exception safe should this action fail.

5. Difference between overloading and overriding.
Let me say this is a horrible question because it is based on one
knowing the technical names for things.

Anyway, overloading is using the same name but a different parameter
list. Overriding uses the same parameter list but where the original
function has been declared virtual in a base class. Overloads are
resolved at compile time, overrides usually at run-time. Overloads can
be particularly useful where one set of code could call either version
according to different circumstances, for example, a template
parameter.

6. Virtual
7. Dynamic binding.

Neither of these are questions. Or does it mean "what are they" in
which case they may as well be asked together, or ask "what is
polymorphism" and perhaps could have been combined with the above
question.

Anyway, the principle is to allow code to call a method by what it does
rather than how it does it, with the actual function that gets called
to be resolved at run-time. The same code that holds a pointer or
reference to a base class could invoke different overloads at different
times, depending on what actual object it has and the type of that
object.

8. Explain the need for a virtual destructor:

The 2nd and 3rd and 5th answers pretty much answer this.

9. Rule of 3.

The first answer answers it best, although the term "user-defined" was
never actually used, but was probably implied. Generally though if it
needs any of the 3 it needs the other two as well.

10. Why do you need a virtual destructor when someone says delete using
a Base ptr thats pointing @ a derived object?

Because the standard says you do.

Nov 27 '06 #4

Syam wrote:
Fully answered interview questions in c and c++ from
http://www.faiqs.com
I think that site must be designed to make the dumbasses look
dumbasser. ;)

The answers are long, jumbled strings of nonsense and when you can
derive some statement from them it is wrong.

I say leave it be...those that read it will become obvious in an
interview even faster than they would before making it easier for
people like me, who are honest about their experience and abilities to
the best of their ability, and for those of us that have to do
interviews.

Nov 27 '06 #5
Earl Purple <ea********@gmail.comwrote:
9. Rule of 3.

The first answer answers it best, although the term "user-defined" was
never actually used, but was probably implied. Generally though if it
needs any of the 3 it needs the other two as well.
I haven't actually checked out the interview question site, but this
article explains why in modern code, one of the 3 is usually a
non-issue, resulting in a "rule of 2":

http://www.artima.com/cppsource/bigtwo.html

--
Marcus Kwok
Replace 'invalid' with 'net' to reply
Nov 27 '06 #6
Marcus Kwok wrote:
Earl Purple <ea********@gmail.comwrote:
>9. Rule of 3.

The first answer answers it best, although the term "user-defined" was
never actually used, but was probably implied. Generally though if it
needs any of the 3 it needs the other two as well.

I haven't actually checked out the interview question site, but this
article explains why in modern code, one of the 3 is usually a
non-issue, resulting in a "rule of 2":

http://www.artima.com/cppsource/bigtwo.html
Hm, interesting piece, but I fail to see the point. They suggest

class Example {
RAII<SomeResourcep_;
RAII<SomeResourcep2_;
public:
Example() :
p_(new SomeResource()),
p2_(new SomeResource()) {}

Example(const Example& other)
: p_(new SomeResource(*other.p_)),
p2_(new SomeResource(*other.p2_)) {}

Example& operator=(const Example& other) {
// Self assignment?
if (this==&other)
return *this;

*p_=*other.p_;
*p2_=*other.p2_;
return *this;
}

~Example() {
std::cout << "Deleting Example, freeing SomeResource!\n";
}
};

where RAII is a variation of auto_ptr<>:

template <typename Tclass RAII {
T* p_;
public:
explicit RAII(T* p) : p_(p) {}

~RAII() {
delete p_;
}

void reset(T* p) {
delete p_;
p_=p;
}

T* get() const {
return p_;
}

T& operator*() const {
return *p_;
}

void swap(RAII& other) {
std::swap(p_,other.p_);
}

private:
RAII(const RAII& other);
RAII& operator=(const RAII& other);
};

So far, I am with them. I can see how their Example class does not need a
destructor since that is taken care of by RAII. What I don't see is how
their Example class differs from:

class Example {
SomeResource p_;
SomeResource p2_;
public:
// compiler provided constructors suffice
~Example() {
std::cout << "Deleting Example, no need to free anything!\n";
}
};

After all, in their assignment operator, they do

*p_=*other.p_;
*p2_=*other.p2_;

which rules out a polymorphic use of the pointers since the assignment would
slice. Thus, the proposed solution can only replace non-polymorphic uses of
pointers and for those offers deep copy semantics. That seems to be
pointless. What is it that I am missing?
Best

Kai-Uwe Bux
Nov 28 '06 #7
Marcus Kwok wrote:
Earl Purple <ea********@gmail.comwrote:
>9. Rule of 3.

The first answer answers it best, although the term "user-defined" was
never actually used, but was probably implied. Generally though if it
needs any of the 3 it needs the other two as well.

I haven't actually checked out the interview question site, but this
article explains why in modern code, one of the 3 is usually a
non-issue, resulting in a "rule of 2":

http://www.artima.com/cppsource/bigtwo.html
Frankly, I've got a number of problems with the article. The fact
that they make an owned pointer class to destruct the thing as
an argument that there is only a RULE of 2 is particularly spurious.

If you are going to make a smart pointer class to handle destruction
why not give it COPY SEMANTICS. Then you can get rid of the
copy constructor and assignment operator as well. With well
designed classes it's usually THREE or NOTHING.
Nov 28 '06 #8

Kai-Uwe Bux wrote:
Marcus Kwok wrote:
Earl Purple <ea********@gmail.comwrote:
9. Rule of 3.

The first answer answers it best, although the term "user-defined" was
never actually used, but was probably implied. Generally though if it
needs any of the 3 it needs the other two as well.
I haven't actually checked out the interview question site, but this
article explains why in modern code, one of the 3 is usually a
non-issue, resulting in a "rule of 2":

http://www.artima.com/cppsource/bigtwo.html

Hm, interesting piece, but I fail to see the point. They suggest

class Example {
RAII<SomeResourcep_;
RAII<SomeResourcep2_;
public:
Example() :
p_(new SomeResource()),
p2_(new SomeResource()) {}

Example(const Example& other)
: p_(new SomeResource(*other.p_)),
p2_(new SomeResource(*other.p2_)) {}

Example& operator=(const Example& other) {
// Self assignment?
if (this==&other)
return *this;

*p_=*other.p_;
*p2_=*other.p2_;
return *this;
}

~Example() {
std::cout << "Deleting Example, freeing SomeResource!\n";
}
};

where RAII is a variation of auto_ptr<>:

template <typename Tclass RAII {
T* p_;
public:
explicit RAII(T* p) : p_(p) {}

~RAII() {
delete p_;
}

void reset(T* p) {
delete p_;
p_=p;
}

T* get() const {
return p_;
}

T& operator*() const {
return *p_;
}

void swap(RAII& other) {
std::swap(p_,other.p_);
}

private:
RAII(const RAII& other);
RAII& operator=(const RAII& other);
};

So far, I am with them. I can see how their Example class does not need a
destructor since that is taken care of by RAII. What I don't see is how
their Example class differs from:

class Example {
SomeResource p_;
SomeResource p2_;
public:
// compiler provided constructors suffice
~Example() {
std::cout << "Deleting Example, no need to free anything!\n";
}
};

After all, in their assignment operator, they do

*p_=*other.p_;
*p2_=*other.p2_;

which rules out a polymorphic use of the pointers since the assignment would
slice. Thus, the proposed solution can only replace non-polymorphic uses of
pointers and for those offers deep copy semantics. That seems to be
pointless. What is it that I am missing?
You are missing the point that when Example has two instances of
SomeResource, then that class must be complete at the point of the
header file, whereas if it is contained in a smart pointer then it can
possibly be incomplete at the class declaration level which can be an
advantage in real life where it is in a separate header file.

There is also no guarantee at the header level that the class
SomeResource is copyable and assignable, but the implementation here
takes advantage of the fact that it is. Otherwise your copy constructor
could be implemented something like other.reset( p->clone() ), which
might allow polymorphic classes too.

Nov 28 '06 #9
Earl Purple wrote:
>
Kai-Uwe Bux wrote:
>Marcus Kwok wrote:
Earl Purple <ea********@gmail.comwrote:
9. Rule of 3.

The first answer answers it best, although the term "user-defined" was
never actually used, but was probably implied. Generally though if it
needs any of the 3 it needs the other two as well.

I haven't actually checked out the interview question site, but this
article explains why in modern code, one of the 3 is usually a
non-issue, resulting in a "rule of 2":

http://www.artima.com/cppsource/bigtwo.html

Hm, interesting piece, but I fail to see the point. They suggest

class Example {
RAII<SomeResourcep_;
RAII<SomeResourcep2_;
public:
Example() :
p_(new SomeResource()),
p2_(new SomeResource()) {}

Example(const Example& other)
: p_(new SomeResource(*other.p_)),
p2_(new SomeResource(*other.p2_)) {}

Example& operator=(const Example& other) {
// Self assignment?
if (this==&other)
return *this;

*p_=*other.p_;
*p2_=*other.p2_;
return *this;
}

~Example() {
std::cout << "Deleting Example, freeing SomeResource!\n";
}
};

where RAII is a variation of auto_ptr<>:

template <typename Tclass RAII {
T* p_;
public:
explicit RAII(T* p) : p_(p) {}

~RAII() {
delete p_;
}

void reset(T* p) {
delete p_;
p_=p;
}

T* get() const {
return p_;
}

T& operator*() const {
return *p_;
}

void swap(RAII& other) {
std::swap(p_,other.p_);
}

private:
RAII(const RAII& other);
RAII& operator=(const RAII& other);
};

So far, I am with them. I can see how their Example class does not need a
destructor since that is taken care of by RAII. What I don't see is how
their Example class differs from:

class Example {
SomeResource p_;
SomeResource p2_;
public:
// compiler provided constructors suffice
~Example() {
std::cout << "Deleting Example, no need to free anything!\n";
}
};

After all, in their assignment operator, they do

*p_=*other.p_;
*p2_=*other.p2_;

which rules out a polymorphic use of the pointers since the assignment
would slice. Thus, the proposed solution can only replace non-polymorphic
uses of pointers and for those offers deep copy semantics. That seems to
be pointless. What is it that I am missing?

You are missing the point that when Example has two instances of
SomeResource, then that class must be complete at the point of the
header file, whereas if it is contained in a smart pointer then it can
possibly be incomplete at the class declaration level which can be an
advantage in real life where it is in a separate header file.
Hm, in that case, this RAII class should just support copy construction and
assignment. Then it would effectively be a wrapper to complete incomplete
types. I have a simple completion<smart pointer template (copy semantics,
no support for polymorphism, guaranteed existence of a pointee, forwarding
of comparison operators) in my library for exactly that purpose. Since it
supports assignment and copy construction, the client class usually needs
none of the Big Three.
There is also no guarantee at the header level that the class
SomeResource is copyable and assignable, but the implementation here
takes advantage of the fact that it is. Otherwise your copy constructor
could be implemented something like other.reset( p->clone() ), which
might allow polymorphic classes too.
For both of those cases, I would just use a run-of-the-shelve smart pointer
like shared_ptr or a copy_ptr. Then again, the compiler generated copy
assignment operator, copy constructor, and destructor would be fine:

class Example {
copy_ptr< SomeResource p_;
copy_ptr< SomeResource p2_;
public:
// compiler provided constructors suffice
~Example() {
std::cout << "Deleting Example, no need to free anything!\n";
}
};

I still don't see how the Rule of Three turns into a Rule of Two. To me,
that appears to be an artifact of the wicked design of their RAII class.
Best

Kai-Uwe Bux
Nov 28 '06 #10

Kai-Uwe Bux wrote:

>
For both of those cases, I would just use a run-of-the-shelve smart pointer
like shared_ptr or a copy_ptr. Then again, the compiler generated copy
assignment operator, copy constructor, and destructor would be fine:

class Example {
copy_ptr< SomeResource p_;
copy_ptr< SomeResource p2_;
public:
// compiler provided constructors suffice
~Example() {
std::cout << "Deleting Example, no need to free anything!\n";
}
};

I still don't see how the Rule of Three turns into a Rule of Two. To me,
that appears to be an artifact of the wicked design of their RAII class.
It could be boost::scoped_ptr. You might want to declare the destructor
and implement it empty but that's not really the same as overloading
it.

#include <boost/scoped_ptr.hpp>
class SomeResource;

class Example
{
boost::scoped_ptr< SomeResource p_;
boost::scoped_ptr< SomeResource p2_;

public:
~Example(); // will be implemented empty
Example ( const Example & );
Example & operator=( const Example & );

// rest of public interface
};

// does deep copy with clone()
// Of course SomeResource is complete at this point.

Example::Example( const Example & x )
: p_( x.p_->clone() ),
p2_( x.p2_->clone() )
{
}

// exception-safe assign in case x.p2_->clone() throws

Example & Example::operator=( const Example & x )
{
Example temp( x );
p_.swap( temp.p_ );
p2_.swap( temp.p2_ );
return *this;
}

Example::~Example()
{
// no need to implement this
}

The only reason that I did put ~Example into the implementation is to
ensure the completeness of SomeResource at the time of its destruction.

Of course, you could use a cloning smart-pointer instead of scoped_ptr,
but the example shows where you might have to implement copy and assign
but not destruction.

Nov 28 '06 #11
"Syam" <sy************@gmail.comwrote in message
news:11*********************@45g2000cws.googlegrou ps.com...
Fully answered interview questions in c and c++ from
http://www.faiqs.com
Judging by the first few C++ answers, the name of this website should be
pronounced "fakes dot com"
Nov 28 '06 #12

Ron Natalie wrote:
Frankly, I've got a number of problems with the article. The fact
that they make an owned pointer class to destruct the thing as
an argument that there is only a RULE of 2 is particularly spurious.

If you are going to make a smart pointer class to handle destruction
why not give it COPY SEMANTICS. Then you can get rid of the
copy constructor and assignment operator as well. With well
designed classes it's usually THREE or NOTHING.
Show me how you would implement clone_ptr< T that will work fully
when T is incomplete?. Note that although it requires T to be complete
on destruction, you can get around that by declaring the destructor in
your class then giving it an empty implementation. I don't know any way
of doing that with copy-construct and assign.

Of course you might decide that even declaring it in the class and
giving it empty implementation still counts as "overriding" thus rule
of 3 not 2.

Plus the fact that not everyone is clever enough to write clone_ptr and
there isn't one I know of in boost, although I think Loki may have one.
(Axter, we don't need yours).

Nov 29 '06 #13
Earl Purple wrote:
>
Ron Natalie wrote:
>
Frankly, I've got a number of problems with the article. The fact
that they make an owned pointer class to destruct the thing as
an argument that there is only a RULE of 2 is particularly spurious.

If you are going to make a smart pointer class to handle destruction
why not give it COPY SEMANTICS. Then you can get rid of the
copy constructor and assignment operator as well. With well
designed classes it's usually THREE or NOTHING.

Show me how you would implement clone_ptr< T that will work fully
when T is incomplete?.
I am willing to take the challenge. However, I am not certain I understand
the requirement "works fully when T is incomplete". Could you provide a
test case that you want to compile and produce specified output so that I
can see whether I am meeting your requirements before posting a solution?
Note that although it requires T to be complete
on destruction, you can get around that by declaring the destructor in
your class then giving it an empty implementation. I don't know any way
of doing that with copy-construct and assign.
Huh? What does "it" refer to: the clone_ptr or T?

[snip]
Best

Kai-Uwe Bux
Nov 29 '06 #14

Kai-Uwe Bux wrote:
Earl Purple wrote:

Show me how you would implement clone_ptr< T that will work fully
when T is incomplete?.

I am willing to take the challenge. However, I am not certain I understand
the requirement "works fully when T is incomplete". Could you provide a
test case that you want to compile and produce specified output so that I
can see whether I am meeting your requirements before posting a solution?
Note that although it requires T to be complete
on destruction, you can get around that by declaring the destructor in
your class then giving it an empty implementation. I don't know any way
of doing that with copy-construct and assign.

Huh? What does "it" refer to: the clone_ptr or T?
The clone_ptr will be complete. T will not be.

This example should work:

// outer.hpp

class Inner;

#include "clone_ptr.hpp"

class Outer
{
clone_ptr< Inner inner;

public:
explicit Outer( int init = 0 );
int get_value() const;
void set_value( int x );

~Outer(); // must be implemented empty
};
// main source file:

#include "outer.hpp"
#include <iostream>

int main()
{
Outer o1( 10 );
Outer o2( o1 );
Outer o3;
o3 = o2; // test assignment
Outer o4( o3 );
o3.set_value( 20 ); // to check we are modifying only a clone

std::cout << "o1=" << o1.get_value() << ", o2=" << o2.get_value()
<< ", o3=" << o3.get_value() << ", o4=" << o4.get_value()
<< '\n';
}

- You should implement the Inner class, outer.cpp and clone_ptr.hpp
- It should output o1=10, o2=10, o3=20, o4=10
- You may not add any more members to the class Outer.

You should also be able to get it to work with 3 different examples of
Inner:
- 1. Where it uses regular copy-construction.
- 2. Where it uses a clone method and Inner is the actual class
- 3. Where it uses a clone method and the actual class created derives
from Inner.

(I will allow you to put clone_ptr into a namespace if you want but
that is the only change you may make)

Nov 30 '06 #15

Earl Purple wrote:
Kai-Uwe Bux wrote:
I am willing to take the challenge. However, I am not certain I understand
the requirement "works fully when T is incomplete". Could you provide a
test case that you want to compile and produce specified output so that I
can see whether I am meeting your requirements before posting a solution?
Note that although it requires T to be complete
on destruction, you can get around that by declaring the destructor in
your class then giving it an empty implementation. I don't know any way
of doing that with copy-construct and assign.
Huh? What does "it" refer to: the clone_ptr or T?

The clone_ptr will be complete. T will not be.
Thinking about it I could probably take up the challenge too. Don't
think it would be the sort of thing most people could do.

My guess is that you would have an abstract class called a cloner and
the complete version on clone_ptr would use its abstract class to do
the cloning in assignment and copying. The cloner would probably also
clone itself at the same time.

There would be a template constructor into which you can pass a some
cloning functor. It would not necessarily be derived from the cloner
interface, but the constructor would be able to create a cloner
implementation from it, a bit like the way it does with the deleter
now.

I guess we could have a default one in case no parameter is passed in.
This would call the copy-constructor. We could also have one that takes
a member function something like:

clone_ptr( T * ptr, &T::clone() )

or whatever. (Perhaps the member function doesn't have to be from the
same class as the pointer).

Now, are we ready to implement all this and submit it to boost?

Nov 30 '06 #16
Earl Purple wrote:
>
Kai-Uwe Bux wrote:
>Earl Purple wrote:
>
Show me how you would implement clone_ptr< T that will work fully
when T is incomplete?.

I am willing to take the challenge. However, I am not certain I
understand the requirement "works fully when T is incomplete". Could you
provide a test case that you want to compile and produce specified output
so that I can see whether I am meeting your requirements before posting a
solution?
Note that although it requires T to be complete
on destruction, you can get around that by declaring the destructor in
your class then giving it an empty implementation. I don't know any way
of doing that with copy-construct and assign.

Huh? What does "it" refer to: the clone_ptr or T?

The clone_ptr will be complete. T will not be.

This example should work:

// outer.hpp

class Inner;

#include "clone_ptr.hpp"

class Outer
{
clone_ptr< Inner inner;

public:
explicit Outer( int init = 0 );
int get_value() const;
void set_value( int x );

~Outer(); // must be implemented empty
};
// main source file:

#include "outer.hpp"
#include <iostream>

int main()
{
Outer o1( 10 );
Outer o2( o1 );
Outer o3;
o3 = o2; // test assignment
Outer o4( o3 );
o3.set_value( 20 ); // to check we are modifying only a clone

std::cout << "o1=" << o1.get_value() << ", o2=" << o2.get_value()
<< ", o3=" << o3.get_value() << ", o4=" << o4.get_value()
<< '\n';
}

- You should implement the Inner class, outer.cpp and clone_ptr.hpp
- It should output o1=10, o2=10, o3=20, o4=10
- You may not add any more members to the class Outer.

You should also be able to get it to work with 3 different examples of
Inner:
- 1. Where it uses regular copy-construction.
- 2. Where it uses a clone method and Inner is the actual class
- 3. Where it uses a clone method and the actual class created derives
from Inner.

(I will allow you to put clone_ptr into a namespace if you want but
that is the only change you may make)
Thanks.
Here is a proof of concept:
// clone_ptr.hpp

#include <algorithm// swap

template < typename T >
void default_delete ( T* p ) {
delete ( p );
}

template < typename T >
T* default_clone ( T* p ) {
return ( p->clone() );
}

template < typename T >
class clone_ptr {
public:

typedef T value_type;
typedef value_type * pointer;
typedef value_type const * const_pointer;
typedef value_type & reference;
typedef value_type const & const_reference;

private:

typedef void (*deleter) ( pointer );
typedef pointer (*cloner) ( pointer );

cloner the_cln;
deleter the_del;
pointer the_ptr;

public:

friend
void swap ( clone_ptr & a, clone_ptr & b ) {
std::swap( a.the_cln, b.the_cln );
std::swap( a.the_del, b.the_del );
std::swap( a.the_ptr, b.the_ptr );
}

explicit
clone_ptr ( pointer ptr )
: the_cln ( &default_clone<value_type)
, the_del ( &default_delete<value_type)
, the_ptr ( ptr )
{}

clone_ptr ( clone_ptr const & other )
: the_cln ( other.the_cln )
, the_del ( other.the_del )
, the_ptr ( other.the_cln( other.the_ptr ) )
{}

clone_ptr & operator= ( clone_ptr const & other ) {
clone_ptr dummy ( other );
swap( dummy, *this );
return ( *this );
}

~clone_ptr ( void ) {
the_del( the_ptr );
}

pointer operator-( void ) {
return ( the_ptr );
}

const_pointer operator-( void ) const {
return ( the_ptr );
}

reference operator* ( void ) {
return ( *the_ptr );
}

const_reference operator* ( void ) const{
return ( *the_ptr );
}

};

// end of file
// inner.hpp

class Inner {

int i;

public:

Inner ( int init )
: i ( init )
{}

int const & item ( void ) const;
int & item ( void );

virtual
Inner* clone ( void ) const;

};

// end of file
// inner.cpp

#include "inner.hpp"

int const & Inner::item ( void ) const {
return ( i );
}

int & Inner::item ( void ) {
return ( i );
}

Inner* Inner::clone ( void ) const {
return ( new Inner ( i ) );
}

// end of file
// outer.hpp

class Inner;

#include "clone_ptr.hpp"

class Outer
{
clone_ptr< Inner inner;

public:
explicit Outer( int init = 0 );
int get_value() const;
void set_value( int x );

~Outer(); // must be implemented empty
};

// end of file
// outer.cpp

#include "outer.hpp"
#include "inner.hpp"

Outer::Outer( int init )
: inner ( new Inner ( init ) )
{}

int Outer::get_value() const {
return ( inner->item() );
return ( 0 );
}

void Outer::set_value( int x ) {
inner->item() = x;
}

Outer::~Outer() {}

// end of file
// main.cpp

#include "outer.hpp"
#include <iostream>

int main()
{
Outer o1( 10 );
Outer o2( o1 );
Outer o3;
o3 = o2; // test assignment
Outer o4( o3 );
o3.set_value( 20 ); // to check we are modifying only a clone

std::cout << "o1=" << o1.get_value() << ", o2=" << o2.get_value()
<< ", o3=" << o3.get_value() << ", o4=" << o4.get_value()
<< '\n';
}

// end of file
g++ -g -c -o inner.o inner.cpp
g++ -g -c -o outer.o outer.cpp
g++ -g main.cpp outer.o inner.o
a.out
o1=10, o2=10, o3=20, o4=10
The above assumes that inner has a method clone(). I think, if clone() is
virtual, the above should also work when you use a class derived from
inner. I have, however, not tested that.

If you want to use the copy constructor from inner, just use:

template < typename T >
T* default_clone ( T* p ) {
return ( new T ( *p ) );
}

If you want to make that work with derived classes, you need a templated
constructor like shared_ptr:
template < typename D >
explicit
clone_ptr ( D* ptr )
: the_cln ( &default_clone<D)
, the_del ( &default_delete<D)
, the_ptr ( ptr )
{}

Again, I have not tested that, yet.
Best

Kai-Uwe Bux
Nov 30 '06 #17

Kai-Uwe Bux wrote:
>
template < typename T >
T* default_clone ( T* p ) {
return ( p->clone() );
}
explicit
clone_ptr ( pointer ptr )
: the_cln ( &default_clone<value_type)
, the_del ( &default_delete<value_type)
, the_ptr ( ptr )
{}
<snip>
The above assumes that inner has a method clone(). I think, if clone() is
virtual, the above should also work when you use a class derived from
inner. I have, however, not tested that.

If you want to use the copy constructor from inner, just use:

template < typename T >
T* default_clone ( T* p ) {
return ( new T ( *p ) );
}

If you want to make that work with derived classes, you need a templated
constructor like shared_ptr:
template < typename D >
explicit
clone_ptr ( D* ptr )
: the_cln ( &default_clone<D)
, the_del ( &default_delete<D)
, the_ptr ( ptr )
{}

Again, I have not tested that, yet.
I would have made the cloner a settable parameter too. I would provide
one by default with the option of having others too. If you're very
clever then you work out whether or not the class has a clone() method.
If it does you use that as the default cloner, if not you use the copy
constructor. Again this would just be the default, so it would be
possible to specify a different cloner, but that would be done by the
constructor.

Your implementation of clone_ptr has not quite passed the test as in
its present state it is intrusive to the way its object clones. I know
we can fix that.

Do you think, by the way, it would be a useful addition to boost?

Nov 30 '06 #18
Earl Purple wrote:
>
Kai-Uwe Bux wrote:
>>
template < typename T >
T* default_clone ( T* p ) {
return ( p->clone() );
}
explicit
clone_ptr ( pointer ptr )
: the_cln ( &default_clone<value_type)
, the_del ( &default_delete<value_type)
, the_ptr ( ptr )
{}
<snip>
>The above assumes that inner has a method clone(). I think, if clone() is
virtual, the above should also work when you use a class derived from
inner. I have, however, not tested that.

If you want to use the copy constructor from inner, just use:

template < typename T >
T* default_clone ( T* p ) {
return ( new T ( *p ) );
}

If you want to make that work with derived classes, you need a templated
constructor like shared_ptr:
template < typename D >
explicit
clone_ptr ( D* ptr )
: the_cln ( &default_clone<D)
, the_del ( &default_delete<D)
, the_ptr ( ptr )
{}

Again, I have not tested that, yet.

I would have made the cloner a settable parameter too. I would provide
one by default with the option of having others too.
Sure.
If you're very clever then you work out whether or not the class has a
clone() method. If it does you use that as the default cloner, if not you
use the copy constructor.

I think, that's a tough one: I know template magic to figure out whether a
type has a clone method. However, I doubt that it works on incomplete
types. For those, the copy constructor would be selected even when a clone
method is available for the complete type.

Again this would just be the default, so it would be
possible to specify a different cloner, but that would be done by the
constructor.

Your implementation of clone_ptr has not quite passed the test as in
its present state it is intrusive to the way its object clones.
I know we can fix that.
What do you mean by "intrusive"?
Do you think, by the way, it would be a useful addition to boost?
Maybe. Here is how I would provide for custom-clone objects and deleters:

// clone_ptr.hpp

#include <algorithm// swap
#include <tr1/functional>

template < typename T >
void default_delete ( T* p ) {
delete ( p );
}

template < typename T >
T* default_clone ( T* p ) {
return ( new T (*p) );
}

template < typename T >
class clone_ptr {
public:

typedef T value_type;
typedef value_type * pointer;
typedef value_type const * const_pointer;
typedef value_type & reference;
typedef value_type const & const_reference;

private:

typedef void (delete_signature) ( pointer );
typedef pointer (clone_signature) ( pointer );
typedef std::tr1::function<delete_signaturedeleter;
typedef std::tr1::function<clone_signature cloner;

cloner the_cln;
deleter the_del;
pointer the_ptr;

public:

friend
void swap ( clone_ptr & a, clone_ptr & b ) {
std::swap( a.the_cln, b.the_cln );
std::swap( a.the_del, b.the_del );
std::swap( a.the_ptr, b.the_ptr );
}

explicit
clone_ptr ( pointer ptr )
: the_cln ( &default_clone<value_type)
, the_del ( &default_delete<value_type)
, the_ptr ( ptr )
{}

template < typename Cloner >
explicit
clone_ptr ( pointer ptr, Cloner c )
: the_cln ( c )
, the_del ( &default_delete<value_type)
, the_ptr ( ptr )
{}

template < typename Cloner, typename Deleter >
explicit
clone_ptr ( pointer ptr, Cloner c, Deleter d )
: the_cln ( c )
, the_del ( d )
, the_ptr ( ptr )
{}

template < typename D >
explicit
clone_ptr ( D* ptr )
: the_cln ( &default_clone<D)
, the_del ( &default_delete<D)
, the_ptr ( ptr )
{}

template < typename D, typename Cloner >
explicit
clone_ptr ( D* ptr, Cloner c )
: the_cln ( c )
, the_del ( &default_delete<value_type)
, the_ptr ( ptr )
{}

template < typename D, typename Cloner, typename Deleter >
explicit
clone_ptr ( D* ptr, Cloner c, Deleter d )
: the_cln ( c )
, the_del ( d )
, the_ptr ( ptr )
{}

clone_ptr ( clone_ptr const & other )
: the_cln ( other.the_cln )
, the_del ( other.the_del )
, the_ptr ( other.the_cln( other.the_ptr ) )
{}

clone_ptr & operator= ( clone_ptr const & other ) {
clone_ptr dummy ( other );
swap( dummy, *this );
return ( *this );
}

~clone_ptr ( void ) {
the_del( the_ptr );
}

pointer operator-( void ) {
return ( the_ptr );
}

const_pointer operator-( void ) const {
return ( the_ptr );
}

reference operator* ( void ) {
return ( *the_ptr );
}

const_reference operator* ( void ) const{
return ( *the_ptr );
}

};

// end of file
Nov 30 '06 #19

Kai-Uwe Bux wrote:
If you're very clever then you work out whether or not the class has a
clone() method. If it does you use that as the default cloner, if not you
use the copy constructor.


I think, that's a tough one: I know template magic to figure out whether a
type has a clone method. However, I doubt that it works on incomplete
types. For those, the copy constructor would be selected even when a clone
method is available for the complete type.
Yes I was thinking that at the time the pointer is attached to it, that
the pointer type must be complete. But there is no real reason why it
should be.
Again this would just be the default, so it would be
possible to specify a different cloner, but that would be done by the
constructor.

Your implementation of clone_ptr has not quite passed the test as in
its present state it is intrusive to the way its object clones.
I know we can fix that.

What do you mean by "intrusive"?
That in this case it forces the templated class to have a clone()
method. Forcing a policy on the templated type isn't always intrusive,
for example, you might say that having a default constructor, an
accessible destructor, being copyable or being assignable are not
intrusive policies, but anything else would probably be considered as
such.
Do you think, by the way, it would be a useful addition to boost?

Maybe. Here is how I would provide for custom-clone objects and deleters:
Its usefulness would depend on whether it really is needed in
production code. I notice that your code does not allow a conversion
from clone_ptr< Derived to clone_ptr< Base but that was not a
requirement and I'm not sure it should be one. Doing so might require
your cloner and deleter to be a base class so that you can call the
clone() and dispose() methods on them without having to pass in a
pointer.

Of course for that to work, it would have to use the virtual clone()
method model to clone the object, not call its copy-constructor which
would slice, however there is already a slicing problem on a base class
pointer which can be overcome by using a protected copy-constructor and
assign thus enforcing clone() to be called. (If the base is abstract of
course copy-construction wouldn't work anyway although assignment could
still slice).

In this case our cloner would have to clone itself as well as its
pointer assuming we don't want to introduce reference-counting into our
clone_ptr.

Nov 30 '06 #20

Kai-Uwe Bux wrote:
I think, that's a tough one: I know template magic to figure out whether a
type has a clone method.
Let's see it...

Nov 30 '06 #21
Noah Roberts wrote:
>
Kai-Uwe Bux wrote:
>I think, that's a tough one: I know template magic to figure out whether
a type has a clone method.

Let's see it...

template < typename T >
class has_clone {
/*
stolen from Rani Sharoni, who attributes this trick to
Richard Smith and also Artem Livshits
*/

typedef char (&no) [1];
typedef char (&yes) [2];

template < typename S, S* ( S::* ) ( void ) >
struct dummy {};

template < typename S >
static
yes check ( dummy< S, &S::clone * );

template < typename S >
static
no check ( ... );

public:

static bool const value = sizeof( check<T>(0) ) == sizeof( yes );

}; // has_clone
#include <iostream>

struct X {

X* clone ( void ) {
return ( new X (*this) );
}

};

struct Y {};

int main ( void ) {
std::cout << has_clone<X>::value << '\n';
std::cout << has_clone<Y>::value << '\n';
}

Of course, it cannot check whether clone() actually clones.
Best

Kai-Uwe Bux
Nov 30 '06 #22
Earl Purple wrote:
>
Kai-Uwe Bux wrote:
If you're very clever then you work out whether or not the class has a
clone() method. If it does you use that as the default cloner, if not
you use the copy constructor.


I think, that's a tough one: I know template magic to figure out whether
a type has a clone method. However, I doubt that it works on incomplete
types. For those, the copy constructor would be selected even when a
clone method is available for the complete type.

Yes I was thinking that at the time the pointer is attached to it, that
the pointer type must be complete. But there is no real reason why it
should be.
Again this would just be the default, so it would be
possible to specify a different cloner, but that would be done by the
constructor.

Your implementation of clone_ptr has not quite passed the test as in
its present state it is intrusive to the way its object clones.
I know we can fix that.

What do you mean by "intrusive"?

That in this case it forces the templated class to have a clone()
method. Forcing a policy on the templated type isn't always intrusive,
for example, you might say that having a default constructor, an
accessible destructor, being copyable or being assignable are not
intrusive policies, but anything else would probably be considered as
such.
Do you think, by the way, it would be a useful addition to boost?

Maybe. Here is how I would provide for custom-clone objects and deleters:

Its usefulness would depend on whether it really is needed in
production code. I notice that your code does not allow a conversion
from clone_ptr< Derived to clone_ptr< Base but that was not a
requirement and I'm not sure it should be one. Doing so might require
your cloner and deleter to be a base class so that you can call the
clone() and dispose() methods on them without having to pass in a
pointer.

Of course for that to work, it would have to use the virtual clone()
method model to clone the object, not call its copy-constructor which
would slice, however there is already a slicing problem on a base class
pointer which can be overcome by using a protected copy-constructor and
assign thus enforcing clone() to be called. (If the base is abstract of
course copy-construction wouldn't work anyway although assignment could
still slice).

In this case our cloner would have to clone itself as well as its
pointer assuming we don't want to introduce reference-counting into our
clone_ptr.
I had thought about about the clone_ptr< Derived to clone_ptr< Base >
problem, too. Here is another approach to that problem. Please, let me know
what you think.

// clone_ptr.hpp

#include <algorithm// swap
#include <tr1/functional>

template < typename T >
void default_delete ( T* p ) {
delete ( p );
}

template < typename T >
T* default_copy ( T* p ) {
return ( new T (*p) );
}

template < typename T >
T* default_clone ( T* p ) {
return ( p->clone() );
}
template < typename T >
class clone_ptr {
public:

typedef T value_type;
typedef value_type * pointer;
typedef value_type const * const_pointer;
typedef value_type & reference;
typedef value_type const & const_reference;

private:

template < typename D >
friend class clone_ptr;
public:

// FIXME: [these should be private]
/*
The member templates below need to know these.
g++ is giving me a hard time to befriend the member
templates. So, for the time being, I make these
typedefs public.
*/

typedef void (delete_signature) ( pointer );
typedef pointer (clone_signature) ( pointer );
typedef std::tr1::function<delete_signaturedeleter;
typedef std::tr1::function<clone_signature cloner;

private:

cloner the_cln;
deleter the_del;
pointer the_ptr;

template < typename D >
struct conversion_delete {

typename clone_ptr<D>::deleter the_deleter;

template < typename P >
conversion_delete ( P d )
: the_deleter ( d )
{}

void operator() ( pointer ptr ) const {
return ( the_deleter( dynamic_cast<D*>( ptr ) ) );
}

};

template < typename D >
struct conversion_clone {

typename clone_ptr<D>::cloner the_cloner;

template < typename P >
conversion_clone ( P c )
: the_cloner ( c )
{}

pointer operator() ( pointer ptr ) const {
return
( static_cast<pointer>
( the_cloner
( dynamic_cast<D*>( ptr ) ) ) );
}

};

public:

friend
void swap ( clone_ptr & a, clone_ptr & b ) {
std::swap( a.the_cln, b.the_cln );
std::swap( a.the_del, b.the_del );
std::swap( a.the_ptr, b.the_ptr );
}

explicit
clone_ptr ( pointer ptr )
: the_cln ( &default_copy<value_type)
, the_del ( &default_delete<value_type)
, the_ptr ( ptr )
{}

template < typename Cloner >
explicit
clone_ptr ( pointer ptr, Cloner c )
: the_cln ( c )
, the_del ( &default_delete<value_type)
, the_ptr ( ptr )
{}

template < typename Cloner, typename Deleter >
explicit
clone_ptr ( pointer ptr, Cloner c, Deleter d )
: the_cln ( c )
, the_del ( d )
, the_ptr ( ptr )
{}

template < typename D >
explicit
clone_ptr ( D* ptr )
: the_cln ( conversion_clone<D>( &default_copy<D) )
, the_del ( conversion_delete<D>( &default_delete<D) )
, the_ptr ( ptr )
{}

template < typename D, typename Cloner >
explicit
clone_ptr ( D* ptr, Cloner c )
: the_cln ( conversion_clone<D>( c ) )
, the_del ( conversion_delete<D>( &default_delete<D) )
, the_ptr ( ptr )
{}

template < typename D, typename Cloner, typename Deleter >
explicit
clone_ptr ( D* ptr, Cloner c, Deleter d )
: the_cln ( conversion_clone<D>( c ) )
, the_del ( conversion_delete<D>( d ) )
, the_ptr ( ptr )
{}

clone_ptr ( clone_ptr const & other )
: the_cln ( other.the_cln )
, the_del ( other.the_del )
, the_ptr ( other.the_cln( other.the_ptr ) )
{}

template < typename D >
clone_ptr ( clone_ptr<Dconst & other )
: the_cln ( conversion_clone<D>( other.the_cln ) )
, the_del ( conversion_delete<D>( other.the_del ) )
, the_ptr ( other.the_ptr )
{}

clone_ptr & operator= ( clone_ptr const & other ) {
clone_ptr dummy ( other );
swap( dummy, *this );
return ( *this );
}

template < typename D >
clone_ptr & operator= ( clone_ptr<Dconst & other ) {
clone_ptr dummy ( other );
swap( dummy, *this );
return ( *this );
}

~clone_ptr ( void ) {
the_del( the_ptr );
}

pointer operator-( void ) {
return ( the_ptr );
}

const_pointer operator-( void ) const {
return ( the_ptr );
}

reference operator* ( void ) {
return ( *the_ptr );
}

const_reference operator* ( void ) const{
return ( *the_ptr );
}

};

// end of file
Best

Kai-Uwe Bux
Dec 1 '06 #23
Kai-Uwe Bux wrote:
[snip]
I had thought about about the clone_ptr< Derived to clone_ptr< Base >
problem, too. Here is another approach to that problem. Please, let me
know what you think.

// clone_ptr.hpp
[snip]
Oops, I had the wrong test code. The proposed solution segfaults in some
cases. So there is a bug somewhere.
Best

Kai-Uwe Bux
Dec 1 '06 #24

Kai-Uwe Bux wrote:
Noah Roberts wrote:

Kai-Uwe Bux wrote:
I think, that's a tough one: I know template magic to figure out whether
a type has a clone method.
Let's see it...


template < typename T >
class has_clone {
/*
stolen from Rani Sharoni, who attributes this trick to
Richard Smith and also Artem Livshits
*/

typedef char (&no) [1];
typedef char (&yes) [2];

template < typename S, S* ( S::* ) ( void ) >
struct dummy {};

template < typename S >
static
yes check ( dummy< S, &S::clone * );

template < typename S >
static
no check ( ... );

public:

static bool const value = sizeof( check<T>(0) ) == sizeof( yes );

}; // has_clone
cute, very cute. There have been times when I wanted something like
this and couldn't think a way up.

Dec 1 '06 #25
Kai-Uwe Bux wrote:
Kai-Uwe Bux wrote:
[snip]
>I had thought about about the clone_ptr< Derived to clone_ptr< Base >
problem, too. Here is another approach to that problem. Please, let me
know what you think.

// clone_ptr.hpp
[snip]
Oops, I had the wrong test code. The proposed solution segfaults in some
cases. So there is a bug somewhere.
I think I fixed it:
// copy_ptr.hpp
// ============
/*
The template copy_ptr<Tdefines smart pointer with copy
semantics: a pointer assignment copies the pointee. It
supports initialization as

copy_ptr<Tp ( new T ( some args ) );

as well as polymorphic initialization via

copy_ptr<Tp ( new D ( some args ) );

where D is derived from T. In this case, copy construction and
assignment are also supported:

copy_ptr<Dd_ptr ( new D ( some args ) );
copy_ptr<Tt_ptr ( d_ptr );
t_ptr = d_ptr;

No slicing will occur when used according to these idioms.
The template allows for specification of a custom cloner
and a custom deleter. The default cloner does not require
T to have a clone method: it uses copy construction to
clone a pointer.
Note: the type T does not need to be complete.
// FIXME: [write more]
*/

#include <algorithm// swap
#include <cassert>
#include <tr1/functional>

template < typename T >
class copy_ptr {
public:

typedef T value_type;
typedef value_type * pointer;
typedef value_type const * const_pointer;
typedef value_type & reference;
typedef value_type const & const_reference;

static
void default_delete ( T* p ) {
delete ( p );
}

static
T* default_copy ( T* p ) {
return ( new T (*p) );
}

static
T* default_clone ( T* p ) {
return ( p->clone() );
}

static
void default_dispose ( T* p ) {
p->dispose();
}

static
T* default_null ( T* p ) {
return ( 0 );
}

static
void default_do_nothing ( T* p ) {
}

private:

template < typename D >
friend class copy_ptr;
public:

// FIXME: [these should be private]
/*
The member templates below need to know these.
g++ is giving me a hard time to befriend the member
templates. So, for the time being, I make these
typedefs public.
*/

typedef void (delete_signature) ( pointer );
typedef pointer (clone_signature) ( pointer );
typedef std::tr1::function<delete_signaturedeleter;
typedef std::tr1::function<clone_signature cloner;

private:

cloner the_cln;
deleter the_del;
pointer the_ptr;
/*
The following templates are used to support
initialization of copy_ptr<Tfrom copy_ptr<D>
where D is derived from T.
*/

template < typename D >
struct conversion_deleter {

typename copy_ptr<D>::deleter the_deleter;

template < typename P >
conversion_deleter ( P d )
: the_deleter ( d )
{}

void operator() ( pointer ptr ) const {
// D* dummy = static_cast<D*>( ptr );
D* dummy = dynamic_cast<D*>( ptr );
// D* dummy = (D*)( ptr );
the_deleter( dummy );
}

}; // conversion_deleter

template < typename D >
struct conversion_cloner {

typename copy_ptr<D>::cloner the_cloner;

template < typename P >
conversion_cloner ( P c )
: the_cloner ( c )
{}

pointer operator() ( pointer ptr ) const {
assert ( ptr != 0 );
// D* dummy = static_cast<D*>( ptr );
D* dummy = dynamic_cast<D*>( ptr );
// D* dummy = (D*)( ptr );
D* clone = the_cloner( dummy );
return ( clone );
}

}; // conversion_cloner

public:

// swap
// ====

friend
void swap ( copy_ptr & a, copy_ptr & b ) {
std::swap( a.the_cln, b.the_cln );
std::swap( a.the_del, b.the_del );
std::swap( a.the_ptr, b.the_ptr );
}
// default constructor [0 pointer]
// ===============================

copy_ptr ( void )
: the_cln ( &default_null )
, the_del ( &default_do_nothing )
, the_ptr ( 0 )
{}
// construction from pointer
// =========================

explicit
copy_ptr ( pointer ptr )
: the_cln ( &default_copy )
, the_del ( &default_delete )
, the_ptr ( ptr )
{
assert ( ptr != 0 );
}

template < typename Cloner >
explicit
copy_ptr ( pointer ptr, Cloner c )
: the_cln ( c )
, the_del ( &default_delete )
, the_ptr ( ptr )
{
assert ( ptr != 0 );
}

template < typename Cloner, typename Deleter >
explicit
copy_ptr ( pointer ptr, Cloner c, Deleter d )
: the_cln ( c )
, the_del ( d )
, the_ptr ( ptr )
{}
// copy constructor
// ================

copy_ptr ( copy_ptr const & other )
: the_cln ( other.the_cln )
, the_del ( other.the_del )
, the_ptr ( other.the_cln( other.the_ptr ) )
{}
// constructor variants from derived types
// =======================================

template < typename D >
explicit
copy_ptr ( D* ptr )
: the_cln ( conversion_cloner<D>
( &copy_ptr<D>::default_copy ) )
, the_del ( conversion_deleter<D>
( &copy_ptr<D>::default_delete ) )
, the_ptr ( ptr )
{
assert ( ptr != 0 );
}

template < typename D, typename Cloner >
explicit
copy_ptr ( D* ptr, Cloner c )
: the_cln ( conversion_cloner<D>( c ) )
, the_del ( conversion_deleter<D>
( &copy_ptr<D>::default_delete ) )
, the_ptr ( ptr )
{
assert ( ptr != 0 );
}

template < typename D, typename Cloner, typename Deleter >
explicit
copy_ptr ( D* ptr, Cloner c, Deleter d )
: the_cln ( conversion_cloner<D>( c ) )
, the_del ( conversion_deleter<D>( d ) )
, the_ptr ( ptr )
{
assert ( ptr != 0 );
}

template < typename D >
copy_ptr ( copy_ptr<Dconst & other )
: the_cln ( conversion_cloner<D>( other.the_cln ) )
, the_del ( conversion_deleter<D>( other.the_del ) )
, the_ptr ( other.the_cln( other.the_ptr ) )
{}
// destructor
// ==========

~copy_ptr ( void ) {
the_del( the_ptr );
}
// copy-swap assignment operators
// ==============================

copy_ptr & operator= ( copy_ptr const & other ) {
copy_ptr dummy ( other );
swap( dummy, *this );
return ( *this );
}

template < typename D >
copy_ptr & operator= ( copy_ptr<Dconst & other ) {
copy_ptr dummy ( other );
swap( dummy, *this );
return ( *this );
}

// dereferencing operators
// =======================

pointer operator-( void ) {
return ( the_ptr );
}

const_pointer operator-( void ) const {
return ( the_ptr );
}

reference operator* ( void ) {
return ( *the_ptr );
}

const_reference operator* ( void ) const{
return ( *the_ptr );
}
// comparison operators
// ====================

// FIXME: [add support for copy_ptr<D>]

bool operator== ( copy_ptr const & other ) const {
return ( the_ptr == other.the_ptr );
}

bool operator!= ( copy_ptr const & other ) const {
return ( the_ptr != other.the_ptr );
}

bool operator< ( copy_ptr const & other ) const {
return ( std::less<pointer>()( the_ptr, other.the_ptr ) );
}

};

// end of file
Comments welcome.
Best

Kai-Uwe Bux

Dec 2 '06 #26

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: softwareengineer2006 | last post by:
All Interview Questions And Answers 10000 Interview Questions And Answers(C,C++,JAVA,DOTNET,Oracle,SAP) I have listed over 10000 interview questions asked in interview/placement test papers for...
0
by: Jobs | last post by:
All answers to the below interview questions are at http://www.geocities.com/dotnetinterviews/ or you can download the complete answer zip file from...
0
by: Jobs | last post by:
Download the JAVA , .NET and SQL Server interview sheet and rate yourself. This will help you judge yourself are you really worth of attending interviews. If you own a company best way to judge if...
0
by: connectrajesh | last post by:
INTERVIEWINFO.NET http://www.interviewinfo.net FREE WEB SITE AND SERVICE FOR JOB SEEKERS /FRESH GRADUATES NO ADVERTISEMENT
2
by: freepdfforjobs | last post by:
Full eBook with 4000 C#, JAVA,.NET and SQL Server Interview questions http://www.questpond.com/SampleInterviewQuestionBook.zip Download the JAVA , .NET and SQL Server interview sheet and rate...
0
by: freesoftwarepdfs | last post by:
Ultimate list of Interview question website.....Do not miss it http://www.questpond.com http://msdotnetsupport.blogspot.com/2007/01/net-interview-questions-by-dutt-part-2.html...
0
by: ramu | last post by:
C# Interview Questions and Answers8 http://allinterviewsbooks.blogspot.com/2008/07/c-interview-questions-and-answers8.html C# Interview Questions and Answers7...
0
by: reema | last post by:
EJB Interview Questions http://interviewdoor.com/technical/EJB-Interview-Questions.htm CSS Interview Questions http://interviewdoor.com/technical/CSS-Interview-Questions.htm C Interview Questions...
0
by: reema | last post by:
EJB Interview Questions http://interviewdoor.com/technical/EJB-Interview-Questions.htm CSS Interview Questions http://interviewdoor.com/technical/CSS-Interview-Questions.htm C Interview Questions...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.