C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

temporaries and copy ctor

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Ian McCulloch
Guest





PostPosted: Thu Nov 24, 2005 8:06 am    Post subject: temporaries and copy ctor Reply with quote




Hi,

In porting some code to g++-3.4, I realized I had, by accident, passed a
temporary of a type with no copy constructor, as a parameter to a function
requiring a const-reference. This isn't allowed: to bind a temporary to a
(const) reference, the copy constructor needs to be accessible.

In my particular case, I have a debugging macro that writes the value of an
expression to a stream, where the call to operator<<() is in the context of
the macro. It would be possible to use say boost::lexical_cast here, but
that requires that the insertion operator to be found by ADL. But it is
not always easy to achieve this (eg, for standard library classes that have
no predefined insertion operator). My rather kludgy solution was to make
instead a macro

#define CONVERT_TO_STRING(x)
(const_cast
so that it is possible to define the insertion operator in the namespace
where the macro expansion occurs, no ADL required.

But, g++-3.4 doesn't like this, because std::ostringstream has no copy
constructor. Argh! This seems to imply that it is not possible to create
a temporary of a type with no copy constructor! That sounds a bit crazy to
me, but nevermind.

Is there some workaround for this? The only thing I can think of is to
write a new class derived from ostream that reimplements std::ostringstream
but has a copy constructor (with something like a shared_ptr to the
buffer), but that seems like overkill. I thought about declaring the
ostringstream in the initializer of a 'for' loop, but that wont work
without seriously refactoring the debugging macro, as it currently requires
the string conversion to be some expression of type convertible to string
and I think it isn't possible to embed a loop in an expression.

Hmm, I just thought of a possible solution:

(untested)

std::string ReturnStringAndDelete(std::ostream& stream)
{
std::string Result(stream.str());
delete &dynamic_cast return Result;
}

#define CONVERT_TO_STRING(x)
ReturnStringAndDelete((*(new std::ostringstream())) << (x))

That doesn't make me very proud though.

Cheers,
Ian McCulloch


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
kanze
Guest





PostPosted: Thu Nov 24, 2005 5:15 pm    Post subject: Re: temporaries and copy ctor Reply with quote



Ian McCulloch wrote:

[...]
Quote:
#define CONVERT_TO_STRING(x)
(const_cast<std::ostringstream&>(std::ostringstream()) << (x)).str()

so that it is possible to define the insertion operator in the
namespace where the macro expansion occurs, no ADL required.

But, g++-3.4 doesn't like this, because std::ostringstream has
no copy constructor. Argh! This seems to imply that it is
not possible to create a temporary of a type with no copy
constructor! That sounds a bit crazy to me, but nevermind.

There's no problem creating the temporary. You can't bind a
temporary to a non const reference, copy constructor or not, and
you cannot bind it to a const reference unless you have a copy
constructor. (The first rule is at least 15 years old, and was
already implemented in CFront 2.1. But many compilers don't
enforce it yet.)

In this case, it is an entirely different rule which is
involved. According to §5.2.11/1: "[...] Conversions that can
be performed explicitly using const_cast are listed below. No
other conversions shall be performed explicitly using
const_cast." And all of the conversions listed require an
lvalue as parameter if the target type is a reference. Since
std::ostringstream() is not an lvalue, the const_cast is
illegal. Period. With or without a copy constructor.

Quote:
Is there some workaround for this?

The usual solution for this sort of thing is something like:
static_cast< ostringstream& >( ostringstream().flush() << (x)
).str()

Note the parentheses -- it is the return value of the <<
operator (an ostream&) which is being converted to an
ostringstream&.

Note to that the problem of binding to a non-const reference is
solved by calling a member function which returns a non-const
reference. In the classical IO streams, the idiom was:
(ostringstream&)( ostringstream() << "" << (x) ).str()
The standardization committee changed the << operator for char
const* from a member to a free function, and broke this.

Quote:
The only thing I can think of is to write a new class derived
from ostream that reimplements std::ostringstream but has a
copy constructor (with something like a shared_ptr to the
buffer), but that seems like overkill.

Well, I use a wrapper class in such cases, but generally because
I also have something significant to do in the destructor.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Michiel.Salters@tomtom.co
Guest





PostPosted: Thu Nov 24, 2005 5:17 pm    Post subject: Re: temporaries and copy ctor Reply with quote




Ian McCulloch wrote:
Quote:

#define CONVERT_TO_STRING(x)
(const_cast<std::ostringstream&>(std::ostringstream()) << (x)).str()

so that it is possible to define the insertion operator in the namespace
where the macro expansion occurs, no ADL required.

But, g++-3.4 doesn't like this, because std::ostringstream has no copy
constructor. Argh! This seems to imply that it is not possible to create
a temporary of a type with no copy constructor! That sounds a bit crazy to
me, but nevermind.

It's wrong. You can create a temporary. However, to const_cast to a
non-const&,
it would first have to bind to a const&, and that part is impossible.

Quote:
Is there some workaround for this?

#define CONVERT_TO_STRING(x)
(std::ostringstream().flush() << (x)).str()

HTH,
Michiel Salters


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Jörg Barfurth
Guest





PostPosted: Thu Nov 24, 2005 5:18 pm    Post subject: Re: temporaries and copy ctor Reply with quote

Hi,

Ian McCulloch schrieb:

Quote:
In porting some code to g++-3.4, I realized I had, by accident, passed a
temporary of a type with no copy constructor, as a parameter to a function
requiring a const-reference. This isn't allowed: to bind a temporary to a
(const) reference, the copy constructor needs to be accessible.


Yes.


Quote:
#define CONVERT_TO_STRING(x)
(const_cast<std::ostringstream&>(std::ostringstream()) << (x)).str()


[...] g++-3.4 doesn't like this, because std::ostringstream has no copy
constructor. Argh! This seems to imply that it is not possible to create
a temporary of a type with no copy constructor! That sounds a bit crazy to
me, but nevermind.


No. You can create a temporary of such a type. But you can't bind it to
a reference. But you can call member functions on it. And inside such a
function *this is an lvalue (even a modifiable one).

Quote:
Is there some workaround for this? The only thing I can think of is to
write a new class derived from ostream that reimplements std::ostringstream
but has a copy constructor (with something like a shared_ptr to the
buffer), but that seems like overkill.

You don't need to reimplement everything. It is enough to provide a way
to get a temporary of that type as lvalue:

template struct Temporary
{
T value;

Temporary() : value() {}
// add (templated) c'tors with arguments as needed

T& lvalue() { return value; }
};

#define CONVERT_TO_STRING(x)
(Temporary<std::ostringstream>().lvalue() << (x)).str()

HTH, Jörg

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Ian McCulloch
Guest





PostPosted: Fri Nov 25, 2005 1:05 pm    Post subject: Re: temporaries and copy ctor Reply with quote

[email]Michiel.Salters (AT) tomtom (DOT) com[/email] wrote:

Quote:

Ian McCulloch wrote:

#define CONVERT_TO_STRING(x)
(const_cast<std::ostringstream&>(std::ostringstream()) << (x)).str()

so that it is possible to define the insertion operator in the namespace
where the macro expansion occurs, no ADL required.

But, g++-3.4 doesn't like this, because std::ostringstream has no copy
constructor. Argh! This seems to imply that it is not possible to
create
a temporary of a type with no copy constructor! That sounds a bit crazy
to me, but nevermind.

It's wrong. You can create a temporary. However, to const_cast to a
non-const&,
it would first have to bind to a const&, and that part is impossible.

No, I think that is not correct. It is not possible to do

std::ostringstream const& s = std::ostringstream();

either (g++ 3.4 reports that the copy constuctor is not accessible). The
const_cast is still illegal though, but that is a separate issue.

Cheers,
Ian


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Maxim Yegorushkin
Guest





PostPosted: Fri Nov 25, 2005 6:20 pm    Post subject: Re: temporaries and copy ctor Reply with quote


Ian McCulloch wrote:

[]

Quote:
#define CONVERT_TO_STRING(x)
(const_cast<std::ostringstream&>(std::ostringstream()) << (x)).str()

so that it is possible to define the insertion operator in the namespace
where the macro expansion occurs, no ADL required.

But, g++-3.4 doesn't like this, because std::ostringstream has no copy
constructor. Argh! This seems to imply that it is not possible to create
a temporary of a type with no copy constructor! That sounds a bit crazy to
me, but nevermind.

Is there some workaround for this?

In this particular case you can hack the c++ type system by exploiting
a stream's member function returning a reference. std::ostream::write()
in the scetch:

(static_cast 1)).str();


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
kanze
Guest





PostPosted: Sat Nov 26, 2005 2:39 pm    Post subject: Re: temporaries and copy ctor Reply with quote

[email]Michiel.Salters (AT) tomtom (DOT) com[/email] wrote:
Quote:
Ian McCulloch wrote:

#define CONVERT_TO_STRING(x)
(const_cast<std::ostringstream&>(std::ostringstream()) << (x)).str()

so that it is possible to define the insertion operator in
the namespace where the macro expansion occurs, no ADL
required.

But, g++-3.4 doesn't like this, because std::ostringstream
has no copy constructor. Argh! This seems to imply that it
is not possible to create a temporary of a type with no copy
constructor! That sounds a bit crazy to me, but nevermind.

It's wrong. You can create a temporary. However, to const_cast
to a non-const&, it would first have to bind to a const&, and
that part is impossible.

That's not the problem here. He doesn't try to bind to a const
reference (or to any reference), and the compiler isn't allowed
to introduce references just because it feals like it. The
problem is simply that the standard lists things that a
const_cast can do, and the requirements for the parameters. And
all const_cast to reference type require an lvalue. Even if
ostringstream had a copy constructor, the const_cast would be
illegal.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Ian McCulloch
Guest





PostPosted: Sat Nov 26, 2005 4:38 pm    Post subject: Re: temporaries and copy ctor Reply with quote

kanze wrote:

Quote:
Michiel.Salters (AT) tomtom (DOT) com wrote:
Ian McCulloch wrote:

#define CONVERT_TO_STRING(x)
(const_cast<std::ostringstream&>(std::ostringstream()) << (x)).str()

so that it is possible to define the insertion operator in
the namespace where the macro expansion occurs, no ADL
required.

But, g++-3.4 doesn't like this, because std::ostringstream
has no copy constructor. Argh! This seems to imply that it
is not possible to create a temporary of a type with no copy
constructor! That sounds a bit crazy to me, but nevermind.

It's wrong. You can create a temporary. However, to const_cast
to a non-const&, it would first have to bind to a const&, and
that part is impossible.

That's not the problem here. He doesn't try to bind to a const
reference (or to any reference), and the compiler isn't allowed
to introduce references just because it feals like it. The
problem is simply that the standard lists things that a
const_cast can do, and the requirements for the parameters. And
all const_cast to reference type require an lvalue. Even if
ostringstream had a copy constructor, the const_cast would be
illegal.

Thanks for the explanation. A followup question, to see if I understand:

Supposing ostringstream had a copy ctor. Or better still, lets do this with
std::string. Is this legal?

template T const& const_ref(T const& x) { return x; }

const_cast<std::string&>(const_ref(std::string())) = "Hello, World!";

What about

const_cast<std::string&>(static_cast<std::string const&>(std::string())) =
"Hello, World!";

?

Cheers,
Ian


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
James Kanze
Guest





PostPosted: Sun Nov 27, 2005 3:59 am    Post subject: Re: temporaries and copy ctor Reply with quote

Ian McCulloch wrote:
Quote:
kanze wrote:

[email]Michiel.Salters (AT) tomtom (DOT) com[/email] wrote:

Ian McCulloch wrote:

#define CONVERT_TO_STRING(x)
(const_cast<std::ostringstream&>(std::ostringstream()) << (x)).str()

so that it is possible to define the insertion operator in
the namespace where the macro expansion occurs, no ADL
required.

But, g++-3.4 doesn't like this, because std::ostringstream
has no copy constructor. Argh! This seems to imply that it
is not possible to create a temporary of a type with no copy
constructor! That sounds a bit crazy to me, but nevermind.

It's wrong. You can create a temporary. However, to
const_cast to a non-const&, it would first have to bind to a
const&, and that part is impossible.

That's not the problem here. He doesn't try to bind to a
const reference (or to any reference), and the compiler isn't
allowed to introduce references just because it feals like it.
The problem is simply that the standard lists things that a
const_cast can do, and the requirements for the parameters.
And all const_cast to reference type require an lvalue. Even
if ostringstream had a copy constructor, the const_cast would
be illegal.

Thanks for the explanation. A followup question, to see if I understand:

Supposing ostringstream had a copy ctor.

I don't think it changes anything *in* this particular case.
There are a lot of cases where it does make a difference; as a
parameter to const_cast just doesn't happen to be one of them.

Quote:
Or better still, lets do this with std::string. Is this
legal?

template T const& const_ref(T const& x) { return x; }

const_cast

That's legal. The function const_ref returns a reference, and a
reference is an lvalue. In this case, I'd say you might as well
go all the way, and write:

template< typename T >
T& lvalue( T const& x ) { return const_cast< T& >( x ) ; }

Formally, this requires that the class in question have a copy
constructor (even though it isn't normally used); not all
compilers enforce this, however.

Quote:
What about

const_cast<std::string&>(static_cast<std::string
const&>(std::string())) =
"Hello, World!";

?

I think that that is legal. There's a rule that says that if
you can write:

T1 x( someExpression ) ;

then static_cast< T1 >( someExpression ) is legal, and has the
same effect, except that the object created is a nameless
temporary. (I'm not sure allowing this particular case was
intentional, but it is a possibly inadvertant consequence of the
rule.)

--
James Kanze mailto: [email]james.kanze (AT) free (DOT) fr[/email]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Ian McCulloch
Guest





PostPosted: Sun Nov 27, 2005 5:51 pm    Post subject: Re: temporaries and copy ctor Reply with quote

James Kanze wrote:

Quote:
Ian McCulloch wrote:

[snip]

Quote:
Or better still, lets do this with std::string. Is this
legal?

template <typename T
T const& const_ref(T const& x) { return x; }

const_cast
That's legal. The function const_ref returns a reference, and a
reference is an lvalue. In this case, I'd say you might as well
go all the way, and write:

template< typename T
T& lvalue( T const& x ) { return const_cast< T& >( x ) ; }

Formally, this requires that the class in question have a copy
constructor (even though it isn't normally used); not all
compilers enforce this, however.

Right. This is in fact exactly the code I had originally, which broke with
g++ 3.4 and ostringstream because of the missing copy ctor. For my post to
c.l.c++.m I 'simplified' it and in doing so accidentally broke it a bit
more ;)

Quote:

What about

const_cast<std::string&>(static_cast<std::string
const&>(std::string())) =
"Hello, World!";

?

I think that that is legal. There's a rule that says that if
you can write:

T1 x( someExpression ) ;

then static_cast< T1 >( someExpression ) is legal, and has the
same effect, except that the object created is a nameless
temporary. (I'm not sure allowing this particular case was
intentional, but it is a possibly inadvertant consequence of the
rule.)

That is interesting. I suspected both would be legal, but I didn't realize
the static_cast would be legal for a different reason. Makes sense though,
I have become accustomed to thinking of xxx_cast<T> as a function, which is
wrong.

Back to the case where there is no copy constructor. And suppose also there
is no convenient member function we can use to get an lvalue from the
temporary, as in the stringstream().flush() trick. Does this work?

template <typename T>
struct base : T
{
T& get() { return *this; }
};

base<std::ostringstream>().get() << x

? g++ 3.4 likes it.

Cheers,
Ian


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
James Kanze
Guest





PostPosted: Mon Nov 28, 2005 8:21 am    Post subject: Re: temporaries and copy ctor Reply with quote

Ian McCulloch wrote:
Quote:
James Kanze wrote:

Back to the case where there is no copy constructor.

Just a nit, but technically speaking, there is always a copy
constructor. If you don't provide one, the compiler will.

I presume you mean "no accessible copy constructor."

Quote:
And suppose also there is no convenient member function we can
use to get an lvalue from the temporary, as in the
stringstream().flush() trick. Does this work?

template <typename T
struct base : T
{
T& get() { return *this; }
};

base
? g++ 3.4 likes it.

As long as T has a default constructor, I see no problems.

--
James Kanze mailto: [email]james.kanze (AT) free (DOT) fr[/email]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Martin Bonner
Guest





PostPosted: Mon Nov 28, 2005 3:51 pm    Post subject: Re: temporaries and copy ctor Reply with quote


James Kanze wrote:
Quote:
Ian McCulloch wrote:
James Kanze wrote:

Back to the case where there is no copy constructor.

Just a nit, but technically speaking, there is always a copy
constructor.
Not always


Quote:
If you don't provide one, the compiler will.

Not if it can't (because you have derived from boost::noncopyable for
example).


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
kanze
Guest





PostPosted: Mon Nov 28, 2005 9:04 pm    Post subject: Re: temporaries and copy ctor Reply with quote

Martin Bonner wrote:
Quote:
James Kanze wrote:
Ian McCulloch wrote:
James Kanze wrote:

Back to the case where there is no copy constructor.

Just a nit, but technically speaking, there is always a copy
constructor.

Not always

If you don't provide one, the compiler will.

Not if it can't (because you have derived from
boost::noncopyable for example).

There's still a declaration. If the compiler requires a
definition, however, it is an error.

Given the way things work, I'll admit that a reasonable program
can't tell the difference.
But the standard says it is there. And it does play a role in
overload resolution:

class Uncopiable
{
Uncopiable( Uncopiable const& ) ;
public:
Uncopiable() {}
} ;

struct Funny : private Uncopiable
{
Funny( int i = 0 ) ;
operator int() { return 0 ; }
} ;

void
f()
{
Funny one ;
Funny two( one ) ;
}

The compiler finds the copy constructor, which is an exact
match, and selects it in overload resolution. And then
generates an error that it cannot generate the definition.

Without a copy constructor, the compiler would choose the
implicit conversion to int, and use tue constructor with int.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Martin Bonner
Guest





PostPosted: Tue Nov 29, 2005 3:51 pm    Post subject: Re: temporaries and copy ctor Reply with quote


kanze wrote:

Quote:
Martin Bonner wrote:

James Kanze wrote:

Ian McCulloch wrote:

James Kanze wrote:



Back to the case where there is no copy constructor.



Just a nit, but technically speaking, there is always a copy
constructor.



Not always



If you don't provide one, the compiler will.



Not if it can't (because you have derived from
boost::noncopyable for example).


There's still a declaration. If the compiler requires a
definition, however, it is an error.

Given the way things work, I'll admit that a reasonable program
can't tell the difference.
But the standard says it is there. And it does play a role in
overload resolution:


[snip example proving the point]

Aaaargh!

No wonder committee members run away screaming if anyone suggests "just
change the name look-up rules to ...".


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.