A Sample auto_ptr implementation

A

Ankur Arora

Hi All,

I'm building a sample application that uses a custom auto_ptr
implementation.
The program crashes with the following output:-

Output (Debug Assertion failed)
----------


release called
copy constructor
aap: ptr2= 10
aap: ptr3= 20
aap: ptr3= 10
aap: exiting app
Deleting pointee...10
Deleting pointee...-572662307 (...problem ?)

Code
--------

#include<iostream>

using namespace std;

// MyAutoPtr Interface
template <class T>
class MyAutoPtr
{
public:

explicit MyAutoPtr(T* ptr=0);

~MyAutoPtr();

template <class U>
MyAutoPtr(MyAutoPtr<U> *rhs);

//copy constructor member template, initialize this member pointer
with any other compatible auto_ptr
template <class U>
MyAutoPtr(MyAutoPtr<U>& rhs);

//assignment operator
template <class U>
MyAutoPtr<T>& operator=(MyAutoPtr<U>& rhs);

//relinquish ownership
T* release();

T* get() const;

//reset the auto_ptr, delete pointee, assume ownership of p
void reset(T* ptr=0);

T& operator*() const;
T* operator->() const;


private:

T* pointee;
//template <class U>
//friend class MyAutoPtr<U>;
};

//Implementation

template<typename T>
inline MyAutoPtr<T>::MyAutoPtr(T* ptr):pointee(ptr)
{ }

template <class T>
inline MyAutoPtr<T>::~MyAutoPtr()
{
if(pointee)
{
cout<<"\n\t Deleting pointee..."<<*pointee;
delete pointee;
}
}

template <class T>
template <class U>
inline MyAutoPtr<T>::MyAutoPtr(MyAutoPtr<U>& rhs) :
pointee(rhs.release())
{
cout<<"\n\t copy constructor";
}

template<class T>
template<class U>
MyAutoPtr<T>& MyAutoPtr<T>::eek:perator=(MyAutoPtr<U>& rhs)
{
cout<<"\n\t Inside operator=";
if(this!=&rhs)
{
cout<<"\n\t Inside operator=, calling reset";
reset(rhs.release());
}
return *this;
}

template <class T>
T* MyAutoPtr<T>::get() const
{
return pointee;
}

template <class T>
inline T& MyAutoPtr<T>::eek:perator *() const
{
return *pointee;
}

template<class T>
inline T* MyAutoPtr<T>::eek:perator->() const
{ return pointee; }

template<class T>
T* MyAutoPtr<T>::release()
{
cout<<"\n\t release called";
T* oldp=pointee;
pointee=0;

return oldp;
}

template<class T>
void MyAutoPtr<T>::reset(T* p)
{
cout<<"\n\t reset called";
if(pointee!=p)
{
delete pointee;
//pointee=0;
}

pointee=p;
}

void main()
{
MyAutoPtr<int> intp(new int(10));
MyAutoPtr<int> intp2(intp);
MyAutoPtr<int> intp3(new int(20));

//cout<<"ptr1= "<<*intp;
cout<<"\n\t aap: ptr2= "<<*intp2;
cout<<"\n\t aap: ptr3= "<<*intp3;

intp3 = intp2; //
==============================> 1

cout<<"\n\t aap: ptr3= "<<*intp3;

cout<<"\n\t aap: exiting app";
}



It seems, on debugging, that class's custom operator= is somehow not
been called at 1 and hence a problem while destructing. (since delete
is being called twice on the same pointer)
---------------------------------------------------------------------------------------------------------

Q1. Any problems with the above code ?
Q2. What is causing operator= not to be called and how to fix it ?
Q3. Following statements (in the class interface) cause compiler
errors, if not commented out

private:
T* pointee;
//template <class U>
//friend class MyAutoPtr<U>;

MSDN defines this error as:-

Compiler Error C3772
Error Message
"name" : invalid friend template declaration

It is invalid to declare a friend of a class template specialization.
You cannot declare an explicit or partial specialization of a class
template and in the same statement declare a friend of that
specialization. The name placeholder identifies the invalid
declaration.
To correct this error
-Do not declare a friend of a class template specialization.
-If appropriate for your application, declare a friend of the class
template, or declare a friend of a particular partial or explicit
specialization.

Why such error, if this is not a specialization? or is it a
specialization somehow?
 
Y

Yakov Gerlovin

Try to define assignment operator without template U parameter:

//assignment operator
MyAutoPtr<T>& operator=(MyAutoPtr<T>& rhs);

Why do you need that 'U' anyway, release should return the pointer to
be passed to reset, so T and U should be equal.
 
K

Kai-Uwe Bux

Ankur said:
Hi All,

I'm building a sample application that uses a custom auto_ptr
implementation.
The program crashes with the following output:-

Output (Debug Assertion failed)
----------


release called
copy constructor
aap: ptr2= 10
aap: ptr3= 20
aap: ptr3= 10
aap: exiting app
Deleting pointee...10
Deleting pointee...-572662307 (...problem ?)

Code
--------

Just a data point: your code works for me with output

release called
copy constructor
aap: ptr2= 10
aap: ptr3= 20
Inside operator=
Inside operator=, calling reset
release called
reset called
aap: ptr3= 10
aap: exiting app
Deleting pointee...10

So I just have nits:

#include<iostream>

using namespace std;

It's a bad idea to use using namespace std in a header.



[snip]
template <class T>
inline MyAutoPtr<T>::~MyAutoPtr()
{
if(pointee)
{
cout<<"\n\t Deleting pointee..."<<*pointee;
delete pointee;
}
}

delete will perform its own check for 0. It is required to be a null-op in
that case.


[snip]
template<class T>
template<class U>
MyAutoPtr<T>& MyAutoPtr<T>::eek:perator=(MyAutoPtr<U>& rhs)
{
cout<<"\n\t Inside operator=";
if(this!=&rhs)

This if-clause will not compile when T and U are different.

You could use

if ( this->pointee == rhs.pointee )

instead (I think).
{
cout<<"\n\t Inside operator=, calling reset";
reset(rhs.release());
}
return *this;
}
[snip]
void main()
[snip]

Main returns int. I get an error with g++ at this point.

It seems, on debugging, that class's custom operator= is somehow not
been called at 1 and hence a problem while destructing. (since delete
is being called twice on the same pointer)

It works with g++.
Q2. What is causing operator= not to be called and how to fix it ?

A bug in your compiler?


[snip]


Best

Kai-Uwe Bux
 
K

Kai-Uwe Bux

Yakov said:
Try to define assignment operator without template U parameter:

//assignment operator
MyAutoPtr<T>& operator=(MyAutoPtr<T>& rhs);

Why do you need that 'U' anyway, release should return the pointer to
be passed to reset, so T and U should be equal.

He needs it to support polymorphism. When D is derived from B, MyAutoPtr<B>
should be constructible and assignable from MyAutoPtr<D>.

But the OP could define copy-constructor and assignment operator from T
separately. For the copy-constructor, I recall that this is needed. I am
not sure if it is needed for the assignment operator.


Best

Kai-Uwe Bux
 
A

anon

[snip]
delete will perform its own check for 0. It is required to be a null-op in
that case.

Check for 0 is required for printing the debug message. Other then that,
the check should be removed
 
A

Ankur Arora

Try to define assignment operator without template U parameter:

//assignment operator
MyAutoPtr<T>& operator=(MyAutoPtr<T>& rhs);

Why do you need that 'U' anyway, release should return the pointer to
be passed to reset, so T and U should be equal.

Hi Yakov,

Thanks for the reply!

Yes indeed when I remove the member template function i.e. change the
function as you suggested, it works.
But I don't know whats the problem with the first version.

I should also mention that I'm using visual studio 2008 express
edition.
This be a compiler issue, u reckon?

Thanks!
 
A

Ankur Arora

Thanks for the reply Kai!
Please see the comments below.

Ankur said:
I'm building a sample application that uses a custom auto_ptr
implementation.
The program crashes with the following output:-
Output               (Debug Assertion failed)
----------
         release called
         copy constructor
         aap: ptr2= 10
         aap: ptr3= 20
         aap: ptr3= 10
         aap: exiting app
         Deleting pointee...10
         Deleting pointee...-572662307         (...problem ?)
Code
--------

Just a data point: your code works for me with output

         release called
         copy constructor
         aap: ptr2= 10
         aap: ptr3= 20
         Inside operator=
         Inside operator=, calling reset
         release called
         reset called
         aap: ptr3= 10
         aap: exiting app
         Deleting pointee...10

So I just have nits:
#include<iostream>
using namespace std;

It's a bad idea to use using namespace std in a header.
Agreed!
[snip]

template <class T>
inline MyAutoPtr<T>::~MyAutoPtr()
{
  if(pointee)
  {
    cout<<"\n\t Deleting pointee..."<<*pointee;
    delete pointee;
   }
}

delete will perform its own check for 0. It is required to be a null-op in
that case.

I did this since removing this check caused the program to crash, even
though I had made pointee equals to 0 in release(), which was used in
the copy constructor.
I'm using visual studio 2008 express edition. You reckon this is a
complier issue?
[snip]
template<class T>
template<class U>
MyAutoPtr<T>& MyAutoPtr<T>::eek:perator=(MyAutoPtr<U>& rhs)
{
  cout<<"\n\t Inside operator=";
  if(this!=&rhs)

This if-clause will not compile when T and U are different.

You could use

  if ( this->pointee == rhs.pointee )

instead (I think).

I saw this example in "More Effective C++" by scott meyers. This was
how its used in that book. Here is a code.

//Interface
template<class T>
class auto_ptr {
public:
explicit auto_ptr(T *p = 0); // see Item 5 for a
// description of
"explicit"
template<class U> // copy constructor member
auto_ptr(auto_ptr<U>& rhs); // template (see Item 28):
// initialize a new
auto_ptr
// with any compatible
// auto_ptr
~auto_ptr();
template<class U> // assignment operator
auto_ptr<T>& // member template (see
operator=(auto_ptr<U>& rhs); // Item 28): assign from
any
// compatible auto_ptr
T& operator*() const; // see Item 28
T* operator->() const; // see Item 28
T* get() const; // return value of current
// dumb pointer
T* release(); // relinquish ownership of
// current dumb pointer
and
// return its value
void reset(T *p = 0); // delete owned pointer;
// assume ownership of p
private:
T *pointee;
template<class U> // make all auto_ptr
classes
friend class auto_ptr<U>; // friends of one another
};

//Implementation
template<class T>
inline auto_ptr<T>::auto_ptr(T *p)
: pointee(p)
{}
template<class T>
inline auto_ptr<T>::auto_ptr(auto_ptr<U>& rhs)
: pointee(rhs.release())
{}
template<class T>
inline auto_ptr<T>::~auto_ptr()
{ delete pointee; }
template<class T>
template<class U>
inline auto_ptr<T>& auto_ptr<T>::eek:perator=(auto_ptr<U>& rhs)
{
if (this != &rhs) reset(rhs.release());
return *this;
}
template<class T>
inline T& auto_ptr<T>::eek:perator*() const
{ return *pointee; }
template<class T>
inline T* auto_ptr<T>::eek:perator->() const
{ return pointee; }
template<class T>
inline T* auto_ptr<T>::get() const
{ return pointee; }
template<class T>
inline T* auto_ptr<T>::release()
{
T *oldPointee = pointee;
pointee = 0;
return oldPointee;
}
template<class T>
inline void auto_ptr<T>::reset(T *p)
{
if (pointee != p) {
delete pointee;
pointee = p;
}
}



Anything wrong with the above ? (would be surprised if there is, as it
came from scott meyers)


It works with g++.

Again, looks like an issue with visual studio 2008 express.
Q2. What is causing operator= not to be called and how to fix it ?

A bug in your compiler?

[snip]

Best

Kai-Uwe Bux
 
B

Barry

Thanks for the reply Kai!
Please see the comments below.

Just a data point: your code works for me with output
         release called
         copy constructor
         aap: ptr2= 10
         aap: ptr3= 20
         Inside operator=
         Inside operator=, calling reset
         release called
         reset called
         aap: ptr3= 10
         aap: exiting app
         Deleting pointee...10
So I just have nits:
It's a bad idea to use using namespace std in a header.
Agreed!
template <class T>
inline MyAutoPtr<T>::~MyAutoPtr()
{
  if(pointee)
  {
    cout<<"\n\t Deleting pointee..."<<*pointee;
    delete pointee;
   }
}
delete will perform its own check for 0. It is required to be a null-op in
that case.

I did this since removing this check caused the program to crash, even
though I had made pointee equals to 0 in release(), which was used in
the copy constructor.
I'm using visual studio 2008 express edition. You reckon this is a
complier issue?




[snip]
template<class T>
template<class U>
MyAutoPtr<T>& MyAutoPtr<T>::eek:perator=(MyAutoPtr<U>& rhs)
{
  cout<<"\n\t Inside operator=";
  if(this!=&rhs)
This if-clause will not compile when T and U are different.
You could use
  if ( this->pointee == rhs.pointee )
instead (I think).

I saw this example in "More Effective C++" by scott meyers. This was
how its used in that book. Here is a code.

//Interface
template<class T>
class auto_ptr {
public:
  explicit auto_ptr(T *p = 0);              // see Item 5 for a
                                            // description of
"explicit"
  template<class U>                         // copy constructor member
  auto_ptr(auto_ptr<U>& rhs);               // template (see Item 28):
                                            // initialize a new
auto_ptr
                                            // with any compatible
                                            // auto_ptr
  ~auto_ptr();
  template<class U>                         // assignment operator
  auto_ptr<T>&                              // member template (see
  operator=(auto_ptr<U>& rhs);              // Item 28): assign from
any
                                            // compatible auto_ptr
  T& operator*() const;                     // see Item 28
  T* operator->() const;                    // see Item 28
  T* get() const;                           // return value of current
                                            // dumb pointer
  T* release();                             // relinquish ownership of
                                            // current dumb pointer
and
                                            // return its value
  void reset(T *p = 0);                     // delete owned pointer;
                                            // assume ownership of p
private:
  T *pointee;
template<class U>                           // make all auto_ptr
classes
friend class auto_ptr<U>;                   // friends of one another

};

//Implementation
template<class T>
inline auto_ptr<T>::auto_ptr(T *p)
: pointee(p)
{}
template<class T>
  inline auto_ptr<T>::auto_ptr(auto_ptr<U>& rhs)
  : pointee(rhs.release())
  {}
template<class T>
inline auto_ptr<T>::~auto_ptr()
{ delete pointee; }
template<class T>
  template<class U>
  inline auto_ptr<T>& auto_ptr<T>::eek:perator=(auto_ptr<U>& rhs)
  {
    if (this != &rhs) reset(rhs.release());
    return *this;
  }
template<class T>
inline T& auto_ptr<T>::eek:perator*() const
{ return *pointee; }
template<class T>
inline T* auto_ptr<T>::eek:perator->() const
{ return pointee; }
template<class T>
inline T* auto_ptr<T>::get() const
{ return pointee; }
template<class T>
inline T* auto_ptr<T>::release()
{
  T *oldPointee = pointee;
  pointee = 0;
  return oldPointee;}

template<class T>
inline void auto_ptr<T>::reset(T *p)
{
  if (pointee != p) {
    delete pointee;
    pointee = p;
  }

}

Anything wrong with the above ? (would be surprised if there is, as it
came from scott meyers)

There's a reversion for auto_ptr (IIRC, a article is proviede by Mayer
on
this), adding auto_ptr_ref for conversion, which supports rvalue
initialization for auto_ptr. which is done transparently.

Again, looks like an issue with visual studio 2008 express.

there are two problem with visual C++ 2005 in this issue:
1. as extension, "explicit" does NOT work as standard says.
needs /Za switch to turn it off.

2. auto_ptr_ref use void* rather T*

point 2 is fixed by VS 2008(none expression version,
but I expression version should ship the same lib)
 
A

Ankur Arora

Thanks for the reply Kai!
Please see the comments below.
Ankur Arora wrote:
Hi All,
I'm building a sample application that uses a custom auto_ptr
implementation.
The program crashes with the following output:-
Output               (Debug Assertion failed)
----------
         release called
         copy constructor
         aap: ptr2= 10
         aap: ptr3= 20
         aap: ptr3= 10
         aap: exiting app
         Deleting pointee...10
         Deleting pointee...-572662307         (....problem ?)
Code
--------
Just a data point: your code works for me with output
         release called
         copy constructor
         aap: ptr2= 10
         aap: ptr3= 20
         Inside operator=
         Inside operator=, calling reset
         release called
         reset called
         aap: ptr3= 10
         aap: exiting app
         Deleting pointee...10
So I just have nits:
#include<iostream>
using namespace std;
It's a bad idea to use using namespace std in a header.
[snip]
template <class T>
inline MyAutoPtr<T>::~MyAutoPtr()
{
  if(pointee)
  {
    cout<<"\n\t Deleting pointee..."<<*pointee;
    delete pointee;
   }
}
delete will perform its own check for 0. It is required to be a null-op in
that case.
I did this since removing this check caused the program to crash, even
though I had made pointee equals to 0 in release(), which was used in
the copy constructor.
I'm using visual studio 2008 express edition. You reckon this is a
complier issue?
[snip]
template<class T>
template<class U>
MyAutoPtr<T>& MyAutoPtr<T>::eek:perator=(MyAutoPtr<U>& rhs)
{
  cout<<"\n\t Inside operator=";
  if(this!=&rhs)
This if-clause will not compile when T and U are different.
You could use
  if ( this->pointee == rhs.pointee )
instead (I think).
I saw this example in "More Effective C++" by scott meyers. This was
how its used in that book. Here is a code.
//Interface
template<class T>
class auto_ptr {
public:
  explicit auto_ptr(T *p = 0);              // see Item 5 for a
                                            // description of
"explicit"
  template<class U>                         // copy constructor member
  auto_ptr(auto_ptr<U>& rhs);               // template (see Item 28):
                                            // initialize a new
auto_ptr
                                            // with any compatible
                                            // auto_ptr
  ~auto_ptr();
  template<class U>                         // assignment operator
  auto_ptr<T>&                              // member template (see
  operator=(auto_ptr<U>& rhs);              // Item 28): assign from
any
                                            // compatible auto_ptr
  T& operator*() const;                     // see Item 28
  T* operator->() const;                    // see Item 28
  T* get() const;                           // return value of current
                                            // dumb pointer
  T* release();                             // relinquish ownership of
                                            // current dumb pointer
and
                                            // return its value
  void reset(T *p = 0);                     // delete owned pointer;
                                            // assume ownership of p
private:
  T *pointee;
template<class U>                           // make all auto_ptr
classes
friend class auto_ptr<U>;                   // friends of one another

//Implementation
template<class T>
inline auto_ptr<T>::auto_ptr(T *p)
: pointee(p)
{}
template<class T>
  inline auto_ptr<T>::auto_ptr(auto_ptr<U>& rhs)
  : pointee(rhs.release())
  {}
template<class T>
inline auto_ptr<T>::~auto_ptr()
{ delete pointee; }
template<class T>
  template<class U>
  inline auto_ptr<T>& auto_ptr<T>::eek:perator=(auto_ptr<U>& rhs)
  {
    if (this != &rhs) reset(rhs.release());
    return *this;
  }
template<class T>
inline T& auto_ptr<T>::eek:perator*() const
{ return *pointee; }
template<class T>
inline T* auto_ptr<T>::eek:perator->() const
{ return pointee; }
template<class T>
inline T* auto_ptr<T>::get() const
{ return pointee; }
template<class T>
inline T* auto_ptr<T>::release()
{
  T *oldPointee = pointee;
  pointee = 0;
  return oldPointee;}
template<class T>
inline void auto_ptr<T>::reset(T *p)
{
  if (pointee != p) {
    delete pointee;
    pointee = p;
  }

Anything wrong with the above ? (would be surprised if there is, as it
came from scott meyers)

There's a reversion for auto_ptr (IIRC, a article is proviede by Mayer
on
this), adding auto_ptr_ref for conversion, which supports rvalue
initialization for auto_ptr. which is done transparently.

void fun(auto_ptr<T> ptr);
fun(auto_ptr(new T)); // rvalue -> auto_ptr_ref -> auto_ptr


Again, looks like an issue with visual studio 2008 express.

there are two problem with visual C++ 2005 in this issue:
1. as extension, "explicit" does NOT work as standard says.
   needs /Za switch to turn it off.

2. auto_ptr_ref use void* rather T*

point 2 is fixed by VS 2008(none expression version,
but I expression version should ship the same lib)


Q2. What is causing operator= not to be called and how to fix it ?
A bug in your compiler?
[snip]

Thanks Barry.
 
B

Barry

Barry said:
[...]
There's a reversion for auto_ptr (IIRC, a article is proviede by Mayer
on
this), adding auto_ptr_ref for conversion, which supports rvalue
initialization for auto_ptr. which is done transparently.

  The guy's name is Scott Meyers and the article is here:
   http://www.aristeia.com/BookErrata/auto_ptr-update.html
[...]
there are two problem with visual C++ 2005 in this issue:
1. as extension, "explicit" does NOT work as standard says.
   needs /Za switch to turn it off.

  Do you have a repro for this? I'd be very interested.

#include <memory>

int main()
{
std::auto_ptr<int> p1 = new int(10); // this shouldn't work
std::auto_ptr<int> p2(new int(10)); // should be like this!
}

=================
d:\>cl /EHsc test.cpp

Compile successfully!
=================

d:\>cl /EHsc /Za test.cpp
cl /EHsc /Za test.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42
for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.

test.cpp
test.cpp(5) : error C2440: 'initializing' : cannot convert from 'int
*' to 'std::auto_ptr<_Ty>'
with
[
_Ty=int
]
Constructor for class 'std::auto_ptr<_Ty>' is declared
'explicit'
with
[
_Ty=int
]

===========================
 
B

Barry

Barry said:
Barry wrote:
[...]
There's a reversion for auto_ptr (IIRC, a article is proviede by Mayer
on
this), adding auto_ptr_ref for conversion, which supports rvalue
initialization for auto_ptr. which is done transparently.
  The guy's name is Scott Meyers and the article is here:
   http://www.aristeia.com/BookErrata/auto_ptr-update.html
[...]
there are two problem with visual C++ 2005 in this issue:
1. as extension, "explicit" does NOT work as standard says.
   needs /Za switch to turn it off.
  Do you have a repro for this? I'd be very interested.
#include <memory>
int main()
{
    std::auto_ptr<int> p1 = new int(10); // this shouldn't work
    std::auto_ptr<int> p2(new int(10));  // should be like this!
}
[...]

  Thanks.
  It doesn't seem to be a compielr bug, though, as a simple
  test with my own class makes the first line fail.

Maybe some Serive Package fix this.
I tried the code on Dinkumware
http://www.dinkumware.com/exam/default.aspx
it fails too.
 
J

James Kanze

He needs it to support polymorphism. When D is derived from B,
MyAutoPtr<B> should be constructible and assignable from
MyAutoPtr<D>.
But the OP could define copy-constructor and assignment
operator from T separately. For the copy-constructor, I recall
that this is needed. I am not sure if it is needed for the
assignment operator.

If I understand the context correctly, it is. A template
operator= will never stop the compiler from generating its
default copy operator=.
 
J

James Kanze

I'm building a sample application that uses a custom auto_ptr
implementation. The program crashes with the following
output:-
Output               (Debug Assertion failed)
----------
         release called
         copy constructor
         aap: ptr2= 10
         aap: ptr3= 20
         aap: ptr3= 10
         aap: exiting app
         Deleting pointee...10
         Deleting pointee...-572662307         (...problem ?)


using namespace std;
// MyAutoPtr Interface
template <class T>
class MyAutoPtr
{
        public:
                explicit MyAutoPtr(T* ptr=0);
                ~MyAutoPtr();
                template <class U>
                MyAutoPtr(MyAutoPtr<U> *rhs);
                //copy constructor member template, initialize
//this member pointer
//with any other compatible auto_ptr
                template <class U>
                MyAutoPtr(MyAutoPtr<U>& rhs);

This is NOT a copy constructor, according to the standard, and
it will not prevent the compiler from generating its default
copy constructor.
                //assignment operator
                template <class U>
                MyAutoPtr<T>& operator=(MyAutoPtr<U>& rhs);

And this is NOT a copy assignment operator, and will not prevent
the compiler from generating its own.

Note that in the two cases above, the compiler will generate its
own versions of the functions, but they will have an argument
type MyAutoPtr<T> const&; not non-const. Which means that in
some cases, when copying, the template version you provide will
be called, rather than the official copy constructor or copy
assignment operator. (I know it sounds wierd, but it's really
rather logical: overload resolution is applied, regardless of
whether the context involves "copying" or not. Template
functions are never considered "copy" operators, but if overload
resolution chooses one, that's what gets called.)
                //relinquish ownership
                T* release();
                T* get() const;
                //reset the auto_ptr, delete pointee, assume ownership of p
                void reset(T* ptr=0);
                T& operator*() const;
                T* operator->() const;
        private:
                T* pointee;
                //template <class U>
                //friend class MyAutoPtr<U>;
};
//Implementation

[... just does the obvious things]
void main()

Shouldn't compile:).
{
        MyAutoPtr<int> intp(new int(10));
        MyAutoPtr<int> intp2(intp);
        MyAutoPtr<int> intp3(new int(20));

Now comes the fun part. Note that all of your instances are for
the same type. So the compiler generated functions will come
into consideration.

Note too that when intp and intp3 go out of scope, they're going
to use a non-array delete on memory that was allocated with an
array new. Undefined behavior.
        //cout<<"ptr1= "<<*intp;
        cout<<"\n\t aap: ptr2= "<<*intp2;
        cout<<"\n\t aap: ptr3= "<<*intp3;
        intp3 = intp2;      // ==============================>  1

        cout<<"\n\t aap: ptr3= "<<*intp3;
        cout<<"\n\t aap: exiting app";
}
It seems, on debugging, that class's custom operator= is
somehow not been called at 1 and hence a problem while
destructing.

This would be a compiler error, but a subtle one. Since intp2
is a non-const lvalue, overload resolution should choose your
template'd operator= over the compiler generated one (which is
none the less present). Given that the context is copy, it
looks like the compiler is using copy assignment operator,
without doing full overload resolution.
(since delete
is being called twice on the same pointer)
--------------------------------------------
Q1. Any problems with the above code ?

IMHO, yes. The fact that you've let the compiler generate its
default versions will lead to runtime errors which may be
difficult to check. (Basically, you can assign a const or a
temporary MyAutoPtr, with the wrong semantics.) At the very
least, you should declare and define the copy constructor and
the assignment operator you want: non-template functions taking
Q2. What is causing operator= not to be called and how to fix
it ?

It looks like a compiler error, but I suspect that my
recommendations concerning Q1 will also fix it.
 
B

Barry

Barry said:
Barry wrote:
Barry wrote: [...]
#include <memory>
int main()
{
    std::auto_ptr<int> p1 = new int(10); // this shouldn't work
    std::auto_ptr<int> p2(new int(10));  // should be like this!
}
[...]
  It doesn't seem to be a compielr bug, though, as a simple
  test with my own class makes the first line fail.
Maybe some Serive Package fix this.
I tried the code on Dinkumware
http://www.dinkumware.com/exam/default.aspx
it fails too.

  Um, I think I've been unclear. The first line compiles with
  'std::auto_ptr<>' but this fails:

    class test {
    public:
      explicit test(void*) {}
    };

    int main()
    {
´    test t1 = new int; // fails
      test t2(new int);  // compiles
      return 0;
    }

  So it's probably not a problem of the compiler, but of the
  std lib implementation that came with it.

yes, it only comes specially with auto_ptr
  Schobi

  P.S.: BTW, never put pointers to arrays into 'std::auto_ptr<>'.

I think you were confused the syntax of "new int(10)" with "new
int[10]"
it mean "new an integer with initial value 10"
 

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

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,058
Latest member
QQXCharlot

Latest Threads

Top