auto_ptr who is right?

B

Barry

struct A
{
void Print() const {
cout << "Print" << endl;
}
};


auto_ptr<A> Get()
{
new A; // (1)
// auto_ptr<A>(new A); // (2) works fine
}

int main()
{
auto_ptr<A> p = Get();
p->Print();
}

if use MSVC8.0 it crash, turns out what p contains is a null pointer
if use STLPort, it works fine,

So is there something wrong with the code, or with MSVC8.0
implementation of auto_ptr ?
 
P

peter koch

struct A
{
void Print() const {
cout << "Print" << endl;
}

};

auto_ptr<A> Get()
{
new A; // (1)
// auto_ptr<A>(new A); // (2) works fine

Don't you respect your compilers warnings? This should not compile
without a warning, and you do not return anything - whats returned is
rubbish.
}

int main()
{
auto_ptr<A> p = Get();
p->Print();
Here you dereference garbage. Garbage in means garbase out.

/Peter

[snip]
 
B

Barry

peter said:
Don't you respect your compilers warnings? This should not compile
without a warning, and you do not return anything - whats returned is
rubbish.

sorry, I didn't compile this code, I just make a mimic example
after I post this thread, I compile this code (add return), and found it
work also on MSVC8
}

int main()
{
auto_ptr<A> p = Get();
p->Print();
Here you dereference garbage. Garbage in means garbase out.

/Peter

[snip]

Well, this one really crashes!

#include <memory>
#include <iostream>
#include <string>

using namespace std;

struct Pizza
{
Pizza(string const& name) : name_(name) {}
void Show() const
{
cout << name_ << " Pizza" << endl;
}
private:
string name_;
};

struct Pie
{
Pie(string const& name) : name_(name) {}
void Show() const
{
cout << name_ << " Pie" << endl;
}
private:
string name_;
};

class AbstractFactory
{
public:
virtual auto_ptr<Pizza> CreatePizza() = 0;

virtual ~AbstractFactory() {}
};

class NestFactory
: public AbstractFactory
{
virtual auto_ptr<Pizza> CreatePizza()
{
return new Pizza("Nest");
}
};

int main()
{
auto_ptr<AbstractFactory> pFactory(new NestFactory);
auto_ptr<Pizza> pPizza = pFactory->CreatePizza();
pPizza->Show();
}
 
B

BobR

Barry said:
sorry, I didn't compile this code, I just make a mimic example
after I post this thread, I compile this code (add return), and found it
work also on MSVC8


Well, this one really crashes!

#include <memory>
#include <iostream>
#include <string>
using namespace std;

struct Pizza{
Pizza(string const& name) : name_(name) {}
void Show() const {
cout << name_ << " Pizza" << endl;
}
private:
string name_;
};
class AbstractFactory{ public:
virtual auto_ptr<Pizza> CreatePizza() = 0;
virtual ~AbstractFactory() {}
};

class NestFactory : public AbstractFactory {
virtual auto_ptr<Pizza> CreatePizza(){

// return new Pizza( "Nest" );
// error: conversion from `Pizza*' to non-scalar type
// `std::auto_ptr<Pizza>' requested
 
B

Barry

BobR said:
// return new Pizza( "Nest" );
// error: conversion from `Pizza*' to non-scalar type
// `std::auto_ptr<Pizza>' requested

return std::auto_ptr<Pizza>( new Pizza( "Nest" ) );

Thanks for your reply, can you tell me where in the standard talk about
this?

And more, why the example in the OP works with MSVC8 while this one does
NOT?
And why all cases works well with STLPort? Is this a bug in STLPort's
auto_ptr?
 
B

BobR

Barry said:
Thanks for your reply, can you tell me where in the standard talk about
this?

And more, why the example in the OP works with MSVC8 while this one does
NOT?

It does NOT work. Did you read what Peter said?

You can't return an object A pointer where it is expected to return an
std::auto_ptr object. If it does compile and run, it's UB.
What you were trying to do is akin to:
std::string Line("Hello World!");
int Number = Line;
And why all cases works well with STLPort? Is this a bug in STLPort's
auto_ptr?

You'll have to ask that where you got STLPort.

Does this compile for you?

// includes here
struct Pizza{
Pizza( std::string const& name) : name_(name) {}
void Show( std::eek:stream &out ) const {
out<<name_<<" Pizza"<<std::endl;
}
private:
std::string name_;
};

class AbstractFactory{ public:
virtual std::auto_ptr<Pizza> CreatePizza() = 0;
virtual Pizza* CreatePizza2() = 0;
virtual ~AbstractFactory() {}
};

class NestFactory : public AbstractFactory{
virtual std::auto_ptr<Pizza> CreatePizza(){
return std::auto_ptr<Pizza>( new Pizza( "Nest" ) );
}
virtual Pizza* CreatePizza2(){
return new Pizza( "Nest2" );
}
};

int main(){
std::auto_ptr<AbstractFactory> pFactory( new NestFactory );
std::auto_ptr<Pizza> pPizza = pFactory->CreatePizza();
pPizza->Show( std::cout );
std::auto_ptr<Pizza> pPizza2( pFactory->CreatePizza2() );
pPizza2->Show( std::cout );
return 0;
} // main()
 
B

Barry

BobR said:
It does NOT work. Did you read what Peter said?

You can't return an object A pointer where it is expected to return an
std::auto_ptr object. If it does compile and run, it's UB.
What you were trying to do is akin to:
std::string Line("Hello World!");
int Number = Line;


You'll have to ask that where you got STLPort.

Does this compile for you?

// includes here
struct Pizza{
Pizza( std::string const& name) : name_(name) {}
void Show( std::eek:stream &out ) const {
out<<name_<<" Pizza"<<std::endl;
}
private:
std::string name_;
};

class AbstractFactory{ public:
virtual std::auto_ptr<Pizza> CreatePizza() = 0;
virtual Pizza* CreatePizza2() = 0;
virtual ~AbstractFactory() {}
};

class NestFactory : public AbstractFactory{
virtual std::auto_ptr<Pizza> CreatePizza(){
return std::auto_ptr<Pizza>( new Pizza( "Nest" ) );
}
virtual Pizza* CreatePizza2(){
return new Pizza( "Nest2" );
}
};

int main(){
std::auto_ptr<AbstractFactory> pFactory( new NestFactory );
std::auto_ptr<Pizza> pPizza = pFactory->CreatePizza();
pPizza->Show( std::cout );
std::auto_ptr<Pizza> pPizza2( pFactory->CreatePizza2() );
pPizza2->Show( std::cout );
return 0;
} // main()

I think it's not that simple as

string Line("dsdsd");
int i = Line;
with auto_ptr

See from the code of auto_ptr from Dinkumware,
it has a explicit constructor
so the return statement find auto_ptr_ref(void*) to construct auto_ptr
then take this auto_ptr_ref to construct auto_ptr.
that's why the code compiles.

but I didn't see anything about the conversion between auto_ptr_ref and
auto_ptr, it seems to be implementation defined.

So what I want to find out is

template <class T>
auto_ptr<T> GetT()
{
return new T;
}

is legal or not? or it's just implementation defined which depends on
the implementation of auto_ptr_ref
 
G

Greg Herlihy

So what I want to find out is

template <class T>
auto_ptr<T> GetT()
{
return new T;

}

is legal or not? or it's just implementation defined which depends on
the implementation of auto_ptr_ref

There is no implicit conversion from a T* to an auto_ptr<T>, because
the auto_ptr constructor that would perform the implicit conversion is
declared "explicit". Therefore, a function returning an auto_ptr must
construct its return value explicitly - as the CreatePizza() routine
that BobR posted, demonstrated:

template <class T>
auto_ptr<T> GetT()
{
return auto_ptr<T>(new T);
}

Greg
 
B

Barry

Greg said:
There is no implicit conversion from a T* to an auto_ptr<T>, because
the auto_ptr constructor that would perform the implicit conversion is
declared "explicit". Therefore, a function returning an auto_ptr must
construct its return value explicitly - as the CreatePizza() routine
that BobR posted, demonstrated:

template <class T>
auto_ptr<T> GetT()
{
return auto_ptr<T>(new T);
}

Well, when I step into the code with MSVC8, the construction path is
T* -> auto_ptr_ref -> auto_ptr
which is done implicitly by the compiler, which is not user-expected.
And because auto_ptr_ref is made to hold ref of auto_ptr, not the
pointer itself, so the construction path is ill formed though it
compiles this way.
 
B

Barry

Greg said:
There is no implicit conversion from a T* to an auto_ptr<T>, because
the auto_ptr constructor that would perform the implicit conversion is
declared "explicit". Therefore, a function returning an auto_ptr must
construct its return value explicitly - as the CreatePizza() routine
that BobR posted, demonstrated:

template <class T>
auto_ptr<T> GetT()
{
return auto_ptr<T>(new T);
}

Greg

Sorry, My bad,
The MSVC8 is broken to report the compile error

#include <memory>

struct A;

struct A_cvt
{
A_cvt(int i)
{
}
};

struct A
{
explicit A(int i) {}
A(A_cvt rhs) {}
};

A GetA()
{
return 1;
}

int main()
{
}

It DO compile the code above. So it makes a construction path
T* -> auto_ptr_ref -> auto_ptr.
which makes me blur about the *explicit* keyword.
 
F

Frank Birbacher

Hi!
It DO compile the code above. So it makes a construction path
T* -> auto_ptr_ref -> auto_ptr.
which makes me blur about the *explicit* keyword.

Any construction path must not include more than _ONE_ implicit
conversion by constructor. Thus the path is illegal and MSVC is wrong.

Frank
 
D

Diego Martins

Hi!


Any construction path must not include more than _ONE_ implicit
conversion by constructor. Thus the path is illegal and MSVC is wrong.

Frank

I also ran into this issue.
It can be avoided if not using MS compiler extensions.
BUT... you have to give up on your <windows> header :(

I want a clean solution to this problem, too.

Diego
HP
 
T

Tobias

Hello,
I have to use Visual Studio 2005 at work:-(. Think, MSVC8 is the
associated compiler.
For me auto_ptr of MSVC was broken. Some static cast instead of the
right dynamic one.
Makes polymorphic use impossible. Maybe, this is fixed in your version
of MSVC.
Best regards,
Tobias
 
F

Frank Birbacher

Hi!
I have to use Visual Studio 2005 at work:-(. Think, MSVC8 is the
associated compiler.
For me auto_ptr of MSVC was broken. Some static cast instead of the
right dynamic one.
Makes polymorphic use impossible. Maybe, this is fixed in your version
of MSVC.

MSVC8 is currently the latest (released) compiler. Could you provide a
little program to show the error?

Frank
 
B

Barry

Tobias said:
Hello,
I have to use Visual Studio 2005 at work:-(. Think, MSVC8 is the
associated compiler.
For me auto_ptr of MSVC was broken. Some static cast instead of the
right dynamic one.
Makes polymorphic use impossible. Maybe, this is fixed in your version
of MSVC.
Best regards,
Tobias

Well,
as I test the code on the Dinkumware Exam
http://www.dinkumware.com/exam/default.aspx
All the VC series produce the right compile error against auto_ptr,
except VC6, which is forgivable. so maybe there's already some Service Pack.
 
T

Tobias

// > MSVC8 is currently the latest (released) compiler. Could you
provide a
// > little program to show the error?
// Try this one with MSVC++ 8.0 and g++ 3.4.4 (or later).
// If both give the same results the error is fixed in your version of
MSVC++.
// If the VC++-Version calls A1::f() this is the error.
// In that case (as I've already mentioned) there is a wrong static
cast in <memory>.

#include<memory>
#include<fstream>

std::eek:fstream log;

struct A1
{
A1() {
log << "A1::A1()\n";
}

virtual void f() {
log << "A1::f() should never be called.\n";
}

virtual ~A1() {
log << "A1::~A1()\n";
}
};

struct A2
{
A2() {
log << "A2::A2()\n";
}

virtual void g() {
log << "A2::g() should be called the first time.\n";
}

virtual ~A2() {
log << "A2::~A2()\n";
}
};

struct B: public A1, public A2
{
B() {
log << "B::B()\n";
}

virtual void g() {
log << "B::g() should be called the second time.\n";
}

virtual ~B() {
log << "B::~B()\n";
}
};

void f(bool b)
{
std::auto_ptr<A2> pA2;

if(b)
pA2 = std::auto_ptr<B>(new B());
else
pA2 = std::auto_ptr<A2>(new A2());

pA2->g();
}

int main()
{
log.open("log");
if(!log) return -1;

f(false);
f(true);

log.close();
return 0;
}
 
B

Barry

Tobias said:
// > MSVC8 is currently the latest (released) compiler. Could you
provide a
// > little program to show the error?
// Try this one with MSVC++ 8.0 and g++ 3.4.4 (or later).
// If both give the same results the error is fixed in your version of
MSVC++.
// If the VC++-Version calls A1::f() this is the error.
// In that case (as I've already mentioned) there is a wrong static
cast in <memory>.

i didn't find the cast you mentioned.
where?
void f(bool b)
{
std::auto_ptr<A2> pA2;

if(b)
pA2 = std::auto_ptr<B>(new B());

actually here should've called

template<class Y> auto_ptr& operator=(auto_ptr<Y>&) throw(); // 20.4.5.1
construct/copy/destroy:

instead of constructing auto_ptr_ref, then
auto_ptr& operator=(auto_ptr_ref<X> r) throw();

It seems auto_ptr_ref in MSVC8 interferes too much
 
T

Tobias

Barry said:
i didn't find the cast you mentioned.
where?

Maybe, I should have said `old-style-cast´ instead of `static cast´
since there is no literal `static_cast´ in <memory>. But the effect is
the same.

Bad things happen in the following snippet of the VC++ version of
<memory>:

8<
template<class _Other>
operator auto_ptr_ref<_Other>() _THROW0()
{ // convert to compatible auto_ptr_ref
_Other *_Testptr = (_Ty *)_Myptr; // test implicit conversion
auto_ptr_ref<_Other> _Ans(&_Myptr);
return (_Testptr != 0 ? _Ans : _Ans);
}
8<
template<class _Ty>
struct auto_ptr_ref
{ // proxy reference for auto_ptr copying
auto_ptr_ref(void *_Right)
: _Ref(_Right)
{ // construct from generic pointer to auto_ptr ptr
}

void *_Ref; // generic pointer to auto_ptr ptr
};

Outch! After some test of object-compatibility the object pointer is
reduced to a void* pointer for later usage. This only works if the
vtable is quite simple. If I'm not mistaken the start of the vtable of
the base class must be equal to the start of the vtable of the derived
class. That is not always the case as we have seen in the example.

It looks better in <memory> of g++:
8<
template<typename _Tp1>
operator auto_ptr_ref said:
8<
template<typename _Tp1>
struct auto_ptr_ref
{
_Tp1* _M_ptr;

explicit
auto_ptr_ref(_Tp1* __p): _M_ptr(__p) { }
};

Regards,
Tobias
 
B

Barry

Tobias said:
8<
template<class _Ty>
struct auto_ptr_ref
{ // proxy reference for auto_ptr copying
auto_ptr_ref(void *_Right)
: _Ref(_Right)
{ // construct from generic pointer to auto_ptr ptr
}

void *_Ref; // generic pointer to auto_ptr ptr
};

Outch! After some test of object-compatibility the object pointer is
reduced to a void* pointer for later usage. This only works if the
vtable is quite simple. If I'm not mistaken the start of the vtable of
the base class must be equal to the start of the vtable of the derived
class. That is not always the case as we have seen in the example.

well, it's a mayor bug also inside auto_ptr implementation in MSVC8
the void* is already changed into Ty* in the VC9 beta. It's seems all
the cases here works fine with it.

anyway, it still uses auto_ptr_ref conversion in your case other than
template<class Y> auto_ptr& operator=(auto_ptr<Y>&) throw();

it's painful using auto_ptr at least with MSVC, while I felt that I'm
defending it.
It's deprecated in the working draft, said that it will be replaced by
unique_ptr, which borrows the new `Move' syntex. Still a long time to wait.
 

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,777
Messages
2,569,604
Members
45,229
Latest member
GloryAngul

Latest Threads

Top