Assignment operator=/copy constructor/temporaries, BROKEN!

  • Thread starter Fabrizio J Bonsignore
  • Start date
A

Alf P. Steinbach /Usenet

* Fabrizio J Bonsignore, on 19.09.2010 04:36:
Fabrizio said:
The other error is similar:
[line] no matching function for call to `AO::AO(AO)'
[line] candidates are: AO::AO(AO&)
[line] AO::AO()
!!! Which is nonsense!

The const is not and was not optional: clause [8.5.3/5] has been in the
standard from the start (1998).

It IS optional even if included in the _description_ of the language.
But I ve been programming C++ since 1992! It was already a well
established language and superior to C, Pascal, Basic, macro
languages...

In 1992 the effective language definition (not yet standardized) was "The
Annotated Reference Manual", popularly called the ARM, by Margaret Ellis and
Bjarne Stroustrup; my copy was published in 1990.

The ARM defined a copy constructor similarly to how the standard does today,
namely that a copy constructor for a class X "can be called with a single
argument of type X". Furthermore, the first formal argument can't be
pass-by-value. Hence, the first formal argument must be passed by reference.

This does not require the formal argument to be 'const', but if the formal
argument isn't 'const' then you can't pass an rvalue as actual argument, since
an rvalue can't be bound to a reference to non-const.

The ARM specified that only an lvalue can be bound to a reference to non-const,
in section §8.4.3.


Cheers & hth.,

- Alf
 
I

Ian Collins

I have another project open, the compiler accepts a copy constructor
and finds it without const and without errors, compile time or run
time. This problem was surprising!

Not really. As Alf pointed out, the copy constructor can use a const or
a non-const reference parameter.
That seems to be a REAL bug in the compiler: the problem is something
different, it should mention the lack of const as a warning (AT MOST,
I insist current practice is to make const optional), and the form of
such error message is so easily detectable that it can be substituted
by anything else in the next error reporting pass, if not completely
changed.

Pass by value to a copy constructor, whether const or not is not
permitted by the language rules. What happens when an object is passed
by value? It gets copied!
 
K

Kai-Uwe Bux

Fabrizio said:
Fabrizio said:
The other error is similar:
[line] no matching function for call to `AO::AO(AO)'
[line] candidates are: AO::AO(AO&)
[line] AO::AO()
!!! Which is nonsense!

The const is not and was not optional: clause [8.5.3/5] has been in the
standard from the start (1998).

It IS optional even if included in the _description_ of the language.

You snipped context, where I explained that [8.5.3/5] implies that your
code _will_ compile and work with "const" but won't without. So, in that
precise sense "const" is _not_optional_ in the code snippet you presented.

Also said:
It SEEMS to work with AO:: (const AO &) in BOTH copy constructor and
assignment operators, the compiler accepts it (compile time), but
const here is almost optional and has been so since ever.

Note the operative word "here", which I took to mean that you are refering
const in the very code snippet under discussion.
But I ve been programming C++ since 1992! It was already a well
established language and superior to C, Pascal, Basic, macro
languages... Adding const was a nuisance then and besides the way C++
is layered, and given access specifiers, well programmed classes will
never have side effect troubles from non sprinkling const liberally! I
insist such is the case that the const_cast<> operator had to be
added.

You are, of course, entitled to your opinion about const. However, note that
you problem does not stem from the introduction of the "const" keyword. It
is a consequence of non-const references not binding to temporaries; and I
have issues with that provision. E.g., I think the following does't make all
that much sense:

typedef std::vector< int > int_vector;
int_vector the_vector;

std::swap( the_vector, int_vector() ); // illegal
the_vector.swap( int_vector() ); // illegal
int_vector().swap( the_vector ); // OK
In any case, standards are complex documents and their link to
actual working and functioning practice is similar to the relationship
between Life and Movies or Literature... Too late... but maybe it
would be worth the while to first describe WORKING languages as they
ARE, then comparatively design a future fantasy, because it seems that
industry standard practice is stronger than **standard documents**.

Apparently, the compilers you are using are rejecting the code without
const. I can only conclude that the standard is actually strong enough to
shape industry practice. (At least in this regard, it did not bring "export"
to the masses, though.)


Best

Kai-Uwe Bux
 
J

James Kanze

I have another project open, the compiler accepts a copy
constructor and finds it without const and without errors,
compile time or run time.

There's no problem defining a copy constructor without const.
You just can't use it to copy rvalues (like the return value of
a function).
Oh, but it DID accept it!

That must be VC++. I recently encountered the same thing:
someone had taken the address of a temporary, and it compiled
under VC++. But failed to compile with g++ (under Linux).

Regardless of what VC++ says, it's not legal C++.

[...]
AO a( &(object.method(argument)).functionReturningAO() );
and it passes compilation. Should I leave it like that?

Only if you're not writing C++, and are sure you'll never have
to compile it with anything other than the compiler you're
currently using. (I wonder if VC++ 10 accepts it. Microsoft is
moving gradually to a policy of respecting the standard.)
 
Ö

Öö Tiib

I have another project open, the compiler accepts a copy constructor
and finds it without const and without errors, compile time or run
time. This problem was surprising! That other class does derive from a
Windows struct and has conversion semantics to it, it defines both
assignment operator= and copy constructor without const... and the
compiler accepts it. I ll have to review that code to see which one of
my cases (in a previous post) I did NOT use in that project that the
compiler did not fail. I am quite liberal in the use of that beefed up
struct as it is now a very basic variable/object in that system and
there has been no such weird error messages. But this may be the case
because it actually IS-A Windows defined struct, so the actual Windows
definition may be affecting compilation. OF COURSE this means to me
more testing...

You probably misunderstood what James did say.

No testing is needed ...
12.8/2: "A non-template constructor for class X is a copy constructor
if its first parameter is of type X&, const X&, volatile X&
or const volatile X&, and either there are no other parameters
or else all other parameters have default arguments (8.3.6)."

Therefore the non-const version is a copy constructor as well. Only
thing is that it can not take temporary as argument. Visual C++ let to
use temporary argument there as "extension". I had to explain to
novice coworkers that exploiting such an "extension" is out of
question and warning about it (at least VS 2005 warns) must be treated
as error.
 
G

Goran

But I ve been programming C++ since 1992! It was already a well
established language and superior to C, Pascal, Basic, macro
languages... Adding const was a nuisance

What a strange thing to say! "const" has been in C++ since forever; it
was picked up from C, a predecessor of C++. "const" exists in other
languages, albeit perhaps not in same form or functionality (arguably
D language does it better, but C heritage of C++ is a PITA).

And it's not a nuisance, but a tool. Some even say that this
particular tool helps them write better code.

Goran.
 
F

Fabrizio J Bonsignore

On 09/19/10 02:25 PM, Fabrizio J Bonsignore wrote:

Not really.  As Alf pointed out, the copy constructor can use a const or
a non-const reference parameter.

Then that was the ARM and if this reference is exact, const was
ancillary, the point is "called with a single argument of type X"
Pass by value to a copy constructor, whether const or not is not
permitted by the language rules.  What happens when an object is passed
by value?  It gets copied!

Indeed! An infinite recursion by necessity or you use bitwise copy at
some point, so why a copy constructor then? But see that strictly
speaking, the statement:

AO x = Function();

should call: the default constructor to build AO x; some copy
constructor to take the AO out of Function() to be used as argument...
to a call to the assignment operator between default constructed x and
the returned COPY of AO from AO Function();!!! Basically we want such
statement to be optimized! But it is supposedly equivalent to:

AO x(Function());

See that const is irrelevant, what matters is that here we need: a
copy constructor to bring the AO object out of Function() AND the
invocation of the copy constructor to place data into x. This seems to
be the case the compiler is confusing so it keeps asking for
AO::AO(AO) and cant see AO::AO(AO &) [no const]: the AO::AO(AO) it
cannot find is... the **copy constructor** before the actual copy
constructor for x; ! Then it seems adding const only helps it select a
case to avoid a spureous call the out-of-function copy constructor.
But ultimately in a REAL sense, the temporary does have a name: its
name is literally speaking

AO AO_BO_Function_void;

underscores more or less, and that is the name we want bound to the
final name _s_ in AO::AO(AO s) {...} or AO::AO(AO &s) {...} or even
AO::AO(const AO &s) {...}

My issue is still that this compiler is inconsistent in what it
accepts. But then I want a statement like AO x = Function(); to MEAN
**the new name of AO_BO_Function_void IS x and &x =
&AO_BO_Function_void**. If the compiler does MOVE the address of
AO_BO_Function_void between its creation and the final binding to name
x, is irrelevant too and system defined as long as this __assignment__
is done efficiently. So, should it call an intermediate function,
assignment operator= or copy constructor in this case? Or is it acting
logically and calling all THREE methods for each statement of the
like?

Note that

AO x;
//some work with x
x = Function();
//some work with new x contents

is expected to call the assignment operator= unambiguously, and the
copy constructor should be just a convenience (bitwise compiler
generated copy OR name binding). x is just a convenience variable
name. But for this statements also the compiler is complaining
accepting both const and non const versions depending on whether const
is used once, once or twice or none at all.

Also note that Function() becomes an expression, not a statement, in
the assignation of value, so something more complex like:

AO x = ((flag)?Retut():Retit());

makes more difficult for the compiler to get the REAL name of the
temporary (also the real name cannot be correctly bound easily in the
definition of Function() unless the compiler determines which of many
possible objects will become the final returned value, though the
compiler must make provisions to assign memory for the final returning
**value** AND garbage it after use). But if that is the problem then
const or pass by reference are just obviating it and the real problem
is to associate some syntax to some optional wrapping code, which was
supposedly a non problem but suddenly is A problem for this compiler!

Danilo J Bonsignore
 
F

Fabrizio J Bonsignore

WOW!

That must be VC++.  I recently encountered the same thing:
someone had taken the address of a temporary, and it compiled
under VC++.  But failed to compile with g++ (under Linux).

It _IS_ compiling in g++ and I cannot test in VC+. The code in
question is the above in this thread, the one defining BO objects as
callers. In the real source the object begun its life as an inner
class talking to another inner class in a singleton static object and
I have no doubt it would compile in VC+, but I had to break the scheme
in g++ just to find out there IS an error message.
 
F

Fabrizio J Bonsignore

12.8/2: "A non-template constructor for class X is a copy constructor
        if its first parameter is of type X&, const X&, volatile X&
        or const volatile X&, and either there are no other parameters
        or else all other parameters have default arguments (8.3.6)."

INDEED! const is optional. g++ 3.4.2 has a bug and it points to a
incomprehension about the language issue or languages in general by
the implementors. Basically, you should be very well versed and
experienced in languages development if you implement a general use
language for the public and it is what all people would expect, not
some personally interesting experimentation to acquire expertise. The
closest reference to the same problem I found is

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44158

A **move** constructor AO::AO(AO &&) seems interesting but is no
solution to a bad implementation of the most basic language defining
feature though!

Danilo J Bonsignore
 
L

LR

Fabrizio said:
WOW!



It _IS_ compiling in g++ and I cannot test in VC+. The code in
question is the above in this thread, the one defining BO objects as
callers. In the real source the object begun its life as an inner
class talking to another inner class in a singleton static object and
I have no doubt it would compile in VC+, but I had to break the scheme
in g++ just to find out there IS an error message.

Sorry I missed the temporary value and non-const reference.

Do you have access to lint?

Looking at the lint errors for the sample code you posted leads me to
some conclusions about the error messages you posted else thread, your
second example was:

[line] no matching function for call to `AO::AO(AO)'
[line] candidates are: AO::AO(AO&)
[line] AO::AO()

Which I think came from a line in your example like:
AO o(Retit());

Which you said was nonsense. After some consideration, I don't think it is.

I think the compiler is trying to tell you that you're trying to
construct something from a temporary here, and then which ctors it tried
to use to match the call.

Can you try adding a line to your code like,
AO o("Hello");
and seeing if you get error messages that with comparison to the above
messages makes the errors easier to understand?


LR
 
J

James Kanze

What a strange thing to say! "const" has been in C++ since
forever; it was picked up from C, a predecessor of C++.

Just a nit, but const wasn't picked up from C. It was present
from the beginning in C++, and was picked up in C from C++.

[...]
And it's not a nuisance, but a tool. Some even say that this
particular tool helps them write better code.

There are particular cases where it is a nuisance, but they're
probably far less frequent than the cases where it helps. At
any rate, because C++ will not initialize a reference to
non-const with a temporary, you pretty much have to use it.
 
J

James Kanze

Then that was the ARM and if this reference is exact, const
was ancillary, the point is "called with a single argument of
type X"

Nothing has changes in this regard since the ARM, or even since
CFront 2.1.
Indeed! An infinite recursion by necessity or you use bitwise
copy at some point, so why a copy constructor then?

An infinite recursion is necessary unless you use pass by
reference or pass by pointer at some point.
But see that strictly speaking, the statement:

AO x = Function();
should call: the default constructor to build AO x; some copy
constructor to take the AO out of Function() to be used as
argument... to a call to the assignment operator between
default constructed x and the returned COPY of AO from AO
Function();!!!

Where do you get that? There's no assignment in that statement;
it's a definition.
Basically we want such statement to be optimized! But it is
supposedly equivalent to:
AO x(Function());

Because the type of the initialization expression is the same as
the type of the variable being initialized, the two ways of
writing the statement are equivalent.
See that const is irrelevant,

No. You still have to call the copy constructor. The copy
constructor has to take a reference to AO. And if this
reference isn't to a const AO, it can't be initialized by
a temporary.

None of this is new; it's been the case for over twenty years.
what matters is that here we need: a copy constructor to bring
the AO object out of Function() AND the invocation of the copy
constructor to place data into x.

Logically, there are two copies involved, one in Function, to
put the return value where class type return values go, and one
in the definition, to copy the value from where return values go
into the new variable. A compiler is allowed to "merge" these
two copies, however, and arrange for Function to construct the
return value directly in the variable; in some cases, there may
be no copy at all (but this depends on what is in Function).
This seems to be the case the compiler is confusing so it
keeps asking for AO::AO(AO) and cant see AO::AO(AO &) [no
const]:

It seems to be the case that you are getting confused (or that
you don't know C++). (Maybe the error message the compiler
gives is confusing, but the issue here isn't.)
the AO::AO(AO) it cannot find is... the **copy constructor**
before the actual copy constructor for x; ! Then it seems
adding const only helps it select a case to avoid a spureous
call the out-of-function copy constructor. But ultimately in
a REAL sense, the temporary does have a name: its name is
literally speaking
AO AO_BO_Function_void;
underscores more or less, and that is the name we want bound to the
final name _s_ in AO::AO(AO s) {...} or AO::AO(AO &s) {...} or even
AO::AO(const AO &s) {...}

I can't make any sense out of the above.
My issue is still that this compiler is inconsistent in what it
accepts.

It seems to be consistent with what the language requires.
But then I want a statement like AO x = Function(); to MEAN
**the new name of AO_BO_Function_void IS x and &x =
&AO_BO_Function_void**. If the compiler does MOVE the address of
AO_BO_Function_void between its creation and the final binding to name
x, is irrelevant too and system defined as long as this __assignment__
is done efficiently.

Are you talking about move semantics? They aren't present in
current C++ yet.
So, should it call an intermediate function,
assignment operator= or copy constructor in this case? Or is it acting
logically and calling all THREE methods for each statement of the
like?

It's probably acting logically, and trying to call the only
constructor it can legally call. (And again, where do you see
assignment. You've written a definition, not an expression
statement, and there is no assignment in it.)
Note that
AO x;
//some work with x
x = Function();
//some work with new x contents
is expected to call the assignment operator= unambiguously,
and the copy constructor should be just a convenience (bitwise
compiler generated copy OR name binding).

The above must call the assignment operator, and not the copy
constructor, in the end. The copy constructor may still be
called within Function, in order to copy the results to where
returned class types are put.
x is just a convenience variable
name. But for this statements also the compiler is complaining
accepting both const and non const versions depending on whether const
is used once, once or twice or none at all.

In this case, the code is legal if the assignment operator takes
a reference to const, or a value; if it takes a value, you might
get an additional copy (but the compiler is also allowed to
optimize this out).
Also note that Function() becomes an expression, not a statement, in
the assignation of value,

The token sequence "Function()" is always an expression.
so something more complex like:
AO x = ((flag)?Retut():Retit());
makes more difficult for the compiler to get the REAL name of the
temporary

Temporaries don't have names.
(also the real name cannot be correctly bound easily in the
definition of Function() unless the compiler determines which of many
possible objects will become the final returned value, though the
compiler must make provisions to assign memory for the final returning
**value** AND garbage it after use).

Typically, I expect that most compilers will optimize the above
so that either Retut or Retit, depending on which one is
actually called, will construct the return value directly in x.
 
J

James Kanze

There's been a lot cut here, but I presume the following refers
to taking an address of a temporary.
It _IS_ compiling in g++ and I cannot test in VC+.

I get a warning with g++ 4.3.4. With Sun CC, it's an error.
It's been an error with every other compiler I've used in the
past. VC++ is the only compiler I've seen which doesn't say
anything about it (and I wouldn't be surprised if that didn't
change in the future---VC++ is moving more and more toward real
conformance).
 
J

James Kanze

INDEED! const is optional.

Yes, but you still have to call the copy contructor. And in
order to call it, you have to bind your expression to its
reference argument. In your example code, you attempt to bind
a temporary to a non-const reference, and that is illegal.
g++ 3.4.2 has a bug.

You've yet to show it.
and it points to a incomprehension about the language issue or
languages in general by the implementors.

The incomprehension about C++ seems to be on your side.
Basically, you should be very well versed and
experienced in languages development if you implement a general use
language for the public and it is what all people would expect, not
some personally interesting experimentation to acquire expertise. The
closest reference to the same problem I found is

That bug concerns move constructors. A very new and still
experimental feature. And not at all relevant to your code.
A **move** constructor AO::AO(AO &&) seems interesting but is
no solution to a bad implementation of the most basic language
defining feature though!

Except that in this case, it is g++ which is correct, and you
that don't understand the language.
 
F

Fabrizio J Bonsignore

On 2010-09-19 19:09:36 -0400, Fabrizio J Bonsignore said:



No, there is no assignment. x is constructed with AO's copy constructor.

Which explicitly ought to read AO x( Function() ); and obviate the
operator = syntax, because such syntax seems to imply rather:

AO &x = *&Function();

or, take the address of the temporary, dereference it and reassign it
as a reference. The temporary was just moved from one implicit alias
to an explicit alias and memory is reused, plus saving a function
call. Anyway both objects are assumed to be built in a frame! And all
these operators are tautological but avoid a copy constructor call.
Not supposedly, that's how it's defined. It's not an optimization.

I am used to think of AO x = Function(); as invoking a useful copy
constructor, but now such copy constructor looks ambiguous! Then AO
x( Function() ); is equivalent to:

AO *pFunction() {... return new AO;}
AO &AO::eek:perator=(AO &x) {if (this==&x) return x; ...}

AO *xp = pFunction(); //save the returned address, like a stack frame
AO &x = xp->operator=( *xp );//assign! instead of calling copy
constructor

or, get the address of the returned object, invoke operator= on it
with itself as argument (!) and assign the result to a reference to
object with the final by-value alias. This IS an assignment
construction, but not a copy (memory) construction, and it is optimum
since we avoid wasting an instance of the relevant object. The copy
constructor, implicit or explicit, here, is wasteful!

So unless the invoked copy constructor does anything beyond bitwise
copy, the call to the constructor is only necessary to move the same
data from one stack frame to another frame? Or to move an address
value and then copy the same data into another heap area with another
address value? This is much clearer using a pointer directly:

AO Function() {
AO *p = new AO; //assign and initialize in the heap
AO &w = *p; //get a by value working reference
.... //do some work on w
return w; //w returns a handle to the memory in p
}

AO &x = *&Function(); //x should point now to the content of *p!

or

AO *pFunction() {... return new AO;}
AO &x = *pFunction(); //&(x) != pFunction() but &x == pFunction() !!

and neither copy nor assignment constructor are called but the
relevant object is still referred to in the program and the assignment
was optimized, though we have to remember to delete &x; later because
it was built in the heap in Function(). A copy constructor here seems
like a way to manage memory so this final delete is not forgotten by
the system nor the user s responsibility...

If we have instead:

AO x; //build a new AO
.... //do process on x
AO z( x ); //copy constructor to get a new copy of x
.... //do process on x and z
x = z; //discard x, call assignment operator...

then both copy constructor and assignment operator= are justified,
distinct and necessary and syntax and semantic match intuitively. We
need two memory areas for AO data. So the choice is between AO z( x );
and AO z = x; !!! Seems just an idiomatic preference, but now it does
not seem to be the same at all if the asignee comes from a function
call returned by value. Then return by value should be avoided for
efficiency and the copy constructor called explicitly always, or
always use pointers as return values and avoid using automatic
objects... which seems to be a bad contract with the language if you
have to avoid a valid construction when it is just a matter of
guaranteeing some efficiency.

I do not think it is very correct if I have to download the _source_
to the compiler, review it, modify it and bootstrap it (if at all
possible with my working version...), because the application is not
implementing well its specification! And then I find basic doubts
about the efficiency of its constructions violating the principle of
explicit semantic, which seems to have confused implementors.

In my simple test case:

*omitting both definitions compiles without trouble

*omitting the copy constructor and const fails the statements:

AO f;
f = Retit(); //no match for 'operator=' in 'f = BO::Retit()()'
f = Retut(); //idem

but accepts

AO m = Retit(); //omitted copy constructor

*omitting the copy constructor and adding const to the assignment
operator= passes.

*omitting the assignment operator= and adding const to the copy
constructor passes.

*omitting the assignment operator= and const fails statements:

AO m = Retit(); //no matching function for call to `AO::AO(AO)'
AO o( Retit() ); //returns a class member

AO f;
f = Retit();

but accepts

AO g = Retut();//!!! returns a temporary built in the stack


*defining both assignment operator= and copy constructor with
signatures

AO &operator=(AO &x);
AO(const AO &x);

fails

f = Retit(); // no match for 'operator=' in 'f = BO::Retit()()'
f = Retut(); // returns member variable

*defining both assignment operator= and copy constructors with
signatures

AO &operator=(const AO &x);
AO(AO &x);

fails to compile

AO m = Retit();
AO o(Retit());
AO g = Retut();
AO h(Retut());
f = Retit();
f = Retut();


but accepts

AO b;
b = BO::a;//assign from member
AO c(a);// should fail too...
AO j = g;


So far in the real code that exposed the bug adding const to the copy
constructor alone compiles, though an unexpected error remains that
crashes the runtime library at exit, beyond reach of the debugger,
because seemingly one destructor fails to be called. Then adding const
to the assigment operator= definition begins complaining about
'discarding qualifiers' inside the operator= definition, in a method
returning a logical bool... I do not want to think templates are
affecting the issue because this three classes system is typical and
autonomous... but it still feels like some internal tree got
twisted...

Danilo J Bonsignore

================================================================================================
F Emporium B, trouble with an employee not wanting to give me Jihad
coffee (Illy, as another employee called it) but ... coffee, which
another employee distinguishes as decaf (normal tasting) from just
coffee ($%@# tasting), then going into a string of complaints and
blaming to names I have never heard.
 
F

Fabrizio J Bonsignore

Which I think came from a line in your example like:
       AO o(Retit());

Which you said was nonsense.  After some consideration, I don't think it is.

Oh, Retit() does nothing, it is not real functional code from any real
application.
I think the compiler is trying to tell you that you're trying to
construct something from a temporary here, and then which ctors it tried
to use to match the call.

Looks like it is trying to find an AO::AO(AO) constructor because of
the reference and temporary relationship, then const here has the real
meaning: leave that temporary alone, do not destroy it, make it const-
ant, keep it steady... til I return from this function, the copy
constructor. But that seems semantic common sense! In such call the
temporary scope IS the call to the copy constructor, it should not go
out of scope (be discarded) til the scope is over (return from the
CC), but then that is why constructors are also defined as a **copy
constructor if its first parameter is of type X& OR const X&...**

Danilo J Bonsignore
 
F

Fabrizio J Bonsignore

You've yet to show it.

Looks like I did! Looking for AO::AO(AO) is meaningless, it is
illegal! It is omitting the normal AO::AO(AO &), no const constructor
the language requires and defines! And it is failing inconsistently. I
can think of cases where an object has to be read const but then in a
defined constructor that s past history, you control it, the user need
not to worry whether its object will be changed or not as argument to
a constructor
The incomprehension about C++ seems to be on your side.
Nope,


That bug concerns move constructors.  A very new and still
experimental feature.  And not at all relevant to your code.

I do like the syntax, but it IS the closest bug report I found
regarding my issue and it is a more **advanced** version, so if I
update... will I get the same error plus new bugs and without the
experimental feature because it is experimental? I think those guys
are trying to solve this problem by extending the language definition
rather than specifying better its implementation or actually MOVING
the implementation code.
Except that in this case, it is g++ which is correct, and you
that don't understand the language.

A compiler is ALWAYS correct in itself! If, the programs it compiles
work as expected (controllably), but it is like saying I can take a
shower whenever I want BUT ONLY if it is raining outside. I understand
the language well enough to find working alternatives, but still this
version is robbing me of a natural idiom and a long time practice and
adding uncertainty if the guys behind it do not know how to fix a
compiler but keep themselves in the place, or worse, if they just keep
coding then waiting to see if nothing went broken. Seems this issue is
so complex some people would like to just fly it away because they do
not understand some people DO understand it.

Danilo J Bonsignore
 
J

Joshua Maurice

<snip rambling and ranting post with poor grammar, punctuation,
spacing, and random capitalization>

First, please read:
http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.8
as Alf suggested. It helps to not be a dick if you're looking for help
from the kindness of strangers.

Then, note that:
T foo();
T x = foo();
does not call T::eek:perator=. It in fact calls T's copy constructor.
This is very much unlike:
T x;
x = foo();
That calls T's default constructor, and then it calls T::eek:perator= on
that default constructed object.

Once you get that, read:
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.9
which explains that the extra copy is likely optimized away, so T's
copy constructor is likely not called either, which results in very
efficient, readable, and maintainable code.
 
B

Bart van Ingen Schenau

I want this to be compilable and working AS IS:

Sorry, but you are out of luck here. The C++ language does not allow
it.
The const-qualification may be optional to be able to create a well-
formed copy-constructor, but that does not mean the const is optional
for all usage patterns of the copy-constructor.
When the source of the copy is a temporary (such as the return value
from a function call), then the const-qualification is most definitely
NOT optional.
class AO
{
public:
       int i;
void Aha();// {i=1;}

AO &operator=(AO &x);// {i=x.i; return *this;}//should not matter if
inline or not

AO();// : i(0) {}
AO(AO &x);// {i=x.i;}
virtual ~AO();// {}

};

void AO::Aha() {
     i=1;
     }

AO::AO()
: i(0) {
       }
AO::AO(AO &x) {
          i=x.i;
          }
AO &AO::eek:perator=(AO &x) {
         i=x.i;
         return *this;
         }
AO::~AO() {}

class BO
{
      AO a;
public:

AO Retit();// {++a.i; return a;}
AO Retut();// {AO z; z.i = 10; return z;}
BO();

};

BO::BO() {
     AO b;
     b = a;
     AO c(a);
     AO d(b);
     AO e(c);

     a.Aha();
     b.Aha();
     c.Aha();
     d.Aha();
     e.Aha();
Up to here, the compiler should not have too many reasons for
complaining.
     AO m = Retit();

Error: No suitable constructor for constructing m from a temporary.
Available, but rejected constructors are:
A0::A0(void)
A0::A0(A0&)
Minimal required, but missing constructor is 'A0::A0(const A0&)'
     AO n = Retit();

Error: No suitable constructor for constructing m from a temporary.
Available, but rejected constructors are:
A0::A0(void)
A0::A0(A0&)
Minimal required, but missing constructor is 'A0::A0(const A0&)'
     AO o(Retit());

Error: No suitable constructor for constructing m from a temporary.
Available, but rejected constructors are:
A0::A0(void)
A0::A0(A0&)
Minimal required, but missing constructor is 'A0::A0(const A0&)'
     AO p = n;
     AO q = o;

     AO f;
     AO g = Retut();

Error: No suitable constructor for constructing m from a temporary.
Available, but rejected constructors are:
A0::A0(void)
A0::A0(A0&)
Minimal required, but missing constructor is 'A0::A0(const A0&)'
     AO h(Retut());

Error: No suitable constructor for constructing m from a temporary.
Available, but rejected constructors are:
A0::A0(void)
A0::A0(A0&)
Minimal required, but missing constructor is 'A0::A0(const A0&)'
     AO j = g;
     AO k = h;

     f = Retit();

Error: No suitable operator=() found.
Available, but rejected operators are:
A0::eek:perator=(A0&)
Possible, but missing signatures are:
A0::eek:perator=(A0)
A0::eek:perator=(const A0&)
     f = Retut();

Error: No suitable operator=() found.
Available, but rejected operators are:
A0::eek:perator=(A0&)
Possible, but missing signatures are:
A0::eek:perator=(A0)
A0::eek:perator=(const A0&)
 
F

Fabrizio J Bonsignore

Then, note that:
T foo();
T x = foo();
does not call T::eek:perator=. It in fact calls T's copy constructor.
This is very much unlike:
T x;
x = foo();
That calls T's default constructor, and then it calls T::eek:perator= on
that default constructed object.

What is assumed is that
AO Function() {return AO();}
AO x = Function();

is equivalent to, or _after optimization_ becomes equivalent to:

AO *pFunction() {return new AO;}

AO &x = *pFunction();
//this is unavoidable but system generated
Remember_System_ToCallDeleteOnThisParticularReferenceObjectsMemory(x);

but is treated as if it was:

T x = foo();

My problem _includes_ pass by value from a function. In the actual
working code I unearthed this bug problem, currently it even seems
there is an EXTRA call to a destructor that is generated by this
temporary optimization, but AFTER the system exits, that may be
matching the spureous message:

no match for 'operator=' in 'f = BO::Retit()()',

after adding const solved the compiling problem (at the expense of
threatening to dichotomize the rest of the library with calls to const
and const_casts).
Once you get that, read:http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.9
which explains that the extra copy is likely optimized away, so T's
copy constructor is likely not called either, which results in very
efficient, readable, and maintainable code.

My point is still that the compiler implementation is confused by the
temporary (optimization) and ends up looking and asking an illegal
constructor signature and/or posts other ambiguous error messages, and
this error was found when using an initialization idiom.

Danilo J Bonsignore
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top