Discussion:
Using assignment operator when rhs is temporary object.
(too old to reply)
Vladimir Grigoriev
2009-10-05 13:27:04 UTC
Permalink
I have found a difference in behavior of a Borland C++ compiler and Visual
C++ 2005 EE compiler.

class A

{

public:

A( int i = 0 ): a( i ) {}

A( A &rhs ): a( rhs.a ) {}

virtual ~A(){}

A & operator=( A &rhs ) // without const!

{

if ( this != &rhs )

{

a = rhs.a;

}


return ( *this );

}

virtual std::ostream & out( std::ostream &os ) const

{

os << a;

return ( os );

}

private:

int a;

};



inline std::ostream & operator<<( std::ostream &os, const A &rhs )

{

return ( rhs.out( os ) );

}

A f()

{

return ( A( 5 ) );

}



int _tmain(int argc, _TCHAR* argv[])

{

A a1( 10 );

A a2;


a2 = f();


return 0;

}



For the Borland C++ compliker the compilation is failed as the compiler does
not find a required function for the assignment statement a2 = f();
because the assignment operator has no attribute const for rhs parameter
while Visual C++ compiles the code without any error.

Which compiler is wrong according to the C++ standard?



Vladimir Grigoriev



Vladimir Grigoriev
Victor Bazarov
2009-10-05 13:50:07 UTC
Permalink
Post by Vladimir Grigoriev
I have found a difference in behavior of a Borland C++ compiler and Visual
C++ 2005 EE compiler.
class A
{
A( int i = 0 ): a( i ) {}
A( A &rhs ): a( rhs.a ) {}
virtual ~A(){}
A & operator=( A &rhs ) // without const!
{
if ( this != &rhs )
{
a = rhs.a;
}
return ( *this );
}
virtual std::ostream & out( std::ostream &os ) const
{
os << a;
return ( os );
}
int a;
};
inline std::ostream & operator<<( std::ostream &os, const A &rhs )
{
return ( rhs.out( os ) );
}
A f()
{
return ( A( 5 ) );
}
int _tmain(int argc, _TCHAR* argv[])
{
A a1( 10 );
A a2;
a2 = f();
return 0;
}
For the Borland C++ compliker the compilation is failed as the compiler does
not find a required function for the assignment statement a2 = f();
because the assignment operator has no attribute const for rhs parameter
while Visual C++ compiles the code without any error.
Which compiler is wrong according to the C++ standard?
Visual C++ is not wrong because you're most likely have C++ extensions
enabled. See in the settings: C/C++ | Language | Disable Language
Extensions. If extensions are not disabled, VC++ allows you to bind a
reference to non-const to a temporary. The Standard does not allow
that. As soon as you disable the extensions, you will get an error from
VC++ as well, IIRC. The problem, of course, is that with extensions
disabled, no Windows header will compile. :-)

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Alex Blekhman
2009-10-05 13:58:10 UTC
Permalink
Post by Victor Bazarov
If extensions are not disabled, VC++ allows you to bind a
reference to non-const to a temporary. The Standard does not
allow that. As soon as you disable the extensions, you will get
an error from VC++ as well, IIRC.
It is enough to enable warning level 4 for the project. With this
settings the compiler emits:

-----
warning C4239: nonstandard extension used : 'argument' :
conversion from 'A' to 'A &'
A non-const reference may only be bound to an lvalue; copy
constructor takes a reference to non-const
-----

which is quite explanatory.

Alex
Vladimir Grigoriev
2009-10-05 14:11:22 UTC
Permalink
Post by Victor Bazarov
Visual C++ is not wrong because you're most likely have C++ extensions
enabled. See in the settings: C/C++ | Language | Disable Language
Extensions. If extensions are not disabled, VC++ allows you to bind a
reference to non-const to a temporary. The Standard does not allow that.
As soon as you disable the extensions, you will get an error from VC++ as
well, IIRC. The problem, of course, is that with extensions disabled, no
Windows header will compile. :-)
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Thanks, Victor.
I have disabled 'Language Extensions'
Now even the copy constructor does not work in the statement

A a = f();

though the Borland compiler allows such code as usual as I think due to
optimization which omits the copy constructor However when the Borland
compiler builds temporary values after exiting a function it uses the copy
constructor without const attribute for rhs. Microsoft C++ with disabled
Language Extensions does allow to do that.

The question arised when I tried to trap paths how auto_ptr performs
assignments and creating objects by copy.

Vladimir Grigoriev.
Vladimir Grigoriev
2009-10-05 14:24:39 UTC
Permalink
I wanted to say
Microsoft C++ with disabled Language Extensions does NOT allow to do that.

Vladimir Grigoriev
Vladimir Grigoriev
2009-10-05 14:43:19 UTC
Permalink
So I have inserted an intermedata structure as it is done in atd::auto_ptr
and some other operators to provide needed conversion

class A

{

private:

struct A_ref

{

A_ref( A &rhs ): r( rhs ) {}

A &r;

};

public:

explicit A( int i = 0 ): a( i ) {}

A( A &rhs ): a( rhs.a ) {}

A( A_ref rhs ) // new constructor

{

a = rhs.r.a;

}

virtual ~A(){}

A & operator=( A &rhs )

{

if ( this != &rhs )

{

a = rhs.a;

}


return ( *this );

}

A & operator=( A_ref ar ) // new assignment operator

{

if ( this != &ar.r )

{

a = ar.r.a;

}

return ( *this );

}

operator A_ref() // new type conversion operator

{

A_ref tmp_r( *this );

return ( tmp_r );

}

virtual std::ostream & out( std::ostream &os ) const

{

os << a;

return ( os );

}

private:

int a;

};



Now an assignment for a temporary object is performed in two steps

1)the type conversion operator is called

2) the assignment operator for A_ref as rhs is called

The copy constructor is substituted for

1) the type conversion operator

2) the constructor for A_ref as argument is called



Vladimir Grigoriev
Ulrich Eckhardt
2009-10-05 14:52:38 UTC
Permalink
Post by Vladimir Grigoriev
The question arised when I tried to trap paths how auto_ptr performs
assignments and creating objects by copy.
Returning an auto_ptr<T> from a function works by bridging the
non-const "copy constructor" with another type. IIRC, the type is called
auto_ptr_ref<T> or auto_ptr<T>::ref. Anyway, what you need is an additional
constructor taking such a type and an implicit conversion to such a type.
Note that the conversion operator may be a non-const member and that it can
still be invoked on a temporary.

See also[1] for a template type that adapts the auto_ptr principle to other
handle types than just pointers. Maybe that code is a bit more readable
than the average C++ stdlib implementation.

Uli

[1] http://lists.boost.org/Archives/boost/2007/11/130127.php
--
C++ FAQ: http://parashift.com/c++-faq-lite

Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
Vladimir Grigoriev
2009-10-05 15:18:01 UTC
Permalink
Thanks, Ulrich

I have seen that I may not do the following with std::auto_ptr

const std::auto_ptr<int> & f()
{
static std::auto_ptr<int> ai( new int( 10 ) );
return ( ai );
}

main()
{
const std::auto_ptr<int> ai = f();
}

Vladimir Grigoriev
Post by Ulrich Eckhardt
Post by Vladimir Grigoriev
The question arised when I tried to trap paths how auto_ptr performs
assignments and creating objects by copy.
Returning an auto_ptr<T> from a function works by bridging the
non-const "copy constructor" with another type. IIRC, the type is called
auto_ptr_ref<T> or auto_ptr<T>::ref. Anyway, what you need is an additional
constructor taking such a type and an implicit conversion to such a type.
Note that the conversion operator may be a non-const member and that it can
still be invoked on a temporary.
See also[1] for a template type that adapts the auto_ptr principle to other
handle types than just pointers. Maybe that code is a bit more readable
than the average C++ stdlib implementation.
Uli
[1] http://lists.boost.org/Archives/boost/2007/11/130127.php
--
C++ FAQ: http://parashift.com/c++-faq-lite
Sator Laser GmbH
Geschaftsfuhrer: Thorsten Focking, Amtsgericht Hamburg HR B62 932
Ulrich Eckhardt
2009-10-05 15:29:39 UTC
Permalink
Post by Vladimir Grigoriev
I have seen that I may not do the following with std::auto_ptr
const std::auto_ptr<int> & f()
{
static std::auto_ptr<int> ai( new int( 10 ) );
return ( ai );
}
main()
{
const std::auto_ptr<int> ai = f();
}
Yes, and? auto_ptr is designed to give exclusive ownership, i.e. that only a
single auto_ptr instance ever has ownership of the pointee. Depending on
how you would like said code to be interpreted, either you would end up
with two auto_ptrs pointing at the same pointee or with an auto_ptr being
modified through a reference-to-const-auto_ptr.

Note: Just in case you want the pointee instead of the pointer to become
const, you need an auto_ptr<int const>.

int* <~> auto_ptr<int>
int const* <~> auto_ptr<int const>
int* const <~> auto_ptr<int> const

Uli
--
C++ FAQ: http://parashift.com/c++-faq-lite

Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
Vladimir Grigoriev
2009-10-05 15:33:11 UTC
Permalink
I am sorry. I did not specify the reference symbol in the definition by
mistake .
All works.

Vladimir Grigoriev
Post by Vladimir Grigoriev
Thanks, Ulrich
I have seen that I may not do the following with std::auto_ptr
const std::auto_ptr<int> & f()
{
static std::auto_ptr<int> ai( new int( 10 ) );
return ( ai );
}
main()
{
const std::auto_ptr<int> ai = f();
}
Vladimir Grigoriev
Post by Ulrich Eckhardt
Post by Vladimir Grigoriev
The question arised when I tried to trap paths how auto_ptr performs
assignments and creating objects by copy.
Returning an auto_ptr<T> from a function works by bridging the
non-const "copy constructor" with another type. IIRC, the type is called
auto_ptr_ref<T> or auto_ptr<T>::ref. Anyway, what you need is an additional
constructor taking such a type and an implicit conversion to such a type.
Note that the conversion operator may be a non-const member and that it can
still be invoked on a temporary.
See also[1] for a template type that adapts the auto_ptr principle to other
handle types than just pointers. Maybe that code is a bit more readable
than the average C++ stdlib implementation.
Uli
[1] http://lists.boost.org/Archives/boost/2007/11/130127.php
--
C++ FAQ: http://parashift.com/c++-faq-lite
Sator Laser GmbH
Geschaftsfuhrer: Thorsten Focking, Amtsgericht Hamburg HR B62 932
Loading...