Why equal operator is not called?

L

linq936

Hi,
I have the following code:

#include <iostream>

using namespace std;

class test
{

public:
int x,y;

test ();

test(const test&);

test operator=(const test&);

virtual ~test();
};

test::test(const test& b)
{
cout << "i am in a copy constructor"<<endl;
}


test::~test()
{
}


test::test()
{
}

test test::eek:perator=(const test& b)
{
if (this == &b)
return *this;
cout << "i am using assignment operator "<<endl;

x = b.x;
y = b.y;

return *this;
}

int main()
{
test d;
test b = d;
test e(b);
getchar();


return 0;
}


When I run it I see

i am in a copy constructor
i am in a copy constructor

So that means that the overloaded equal operator function is not
called.

Why is that? Is this compiler dependent? I am using g++. Is there
any document to describe the underline mechanic?
 
A

Alf P. Steinbach

* linq936:
When I run it I see

i am in a copy constructor
i am in a copy constructor

So that means that the overloaded equal operator function is not
called.

Why is that?

You never call it -- there is no assignment to any "test" object in
your program.

By the way, let the assignment operator return a reference, not a value.

Cheers, & hth.,

- Alf
 
C

Colin Song

Hi,
I have the following code:

#include <iostream>

using namespace std;

class test
{

public:
int x,y;

test ();

test(const test&);

test operator=(const test&);

virtual ~test();

};

test::test(const test& b)
{
cout << "i am in a copy constructor"<<endl;

}

test::~test()
{

}

test::test()
{

}

test test::eek:perator=(const test& b)
{
if (this == &b)
return *this;
cout << "i am using assignment operator "<<endl;

x = b.x;
y = b.y;

return *this;

}

int main()
{
test d;
test b = d;
test e(b);
getchar();

return 0;

}

When I run it I see

i am in a copy constructor
i am in a copy constructor

So that means that the overloaded equal operator function is not
called.

Why is that? Is this compiler dependent? I am using g++. Is there
any document to describe the underline mechanic?

try
int main()
{
test d;
test b;
b=d;
getchar();
return 0;
}

"test b=d;" will call the copy constructor.
 
B

Barry

linq936 said:
Hi,
I have the following code:

#include <iostream>

using namespace std;

class test
{

public:
int x,y;

test ();

test(const test&);

test operator=(const test&);

virtual ~test();
};

test::test(const test& b)
{
cout << "i am in a copy constructor"<<endl;
}


test::~test()
{
}


test::test()
{
}

test test::eek:perator=(const test& b)
{
if (this == &b)
return *this;
cout << "i am using assignment operator "<<endl;

x = b.x;
y = b.y;

return *this;
}

int main()
{
test d;
test b = d;

the syntax is confusing.
actually it's equivalent to

test b(d);

then it's clear that here copy-ctor is called

if you want assignment operator called, then write:

test b;
b = d;
 
J

James Kanze

I have the following code:
#include <iostream>
using namespace std;
class test
{
public:
int x,y;

test ();
test(const test&);
test operator=(const test&);

This should almost certainly return test& (or possibly test
const&).
virtual ~test();
};
test::test(const test& b)
{
cout << "i am in a copy constructor"<<endl;
}


test test::eek:perator=(const test& b)
{
if (this == &b)
return *this;

Just a nit, but the test for self assignment isn't really
necessary. Neither here, nor in general.
cout << "i am using assignment operator "<<endl;
x = b.x;
y = b.y;
return *this;
}
int main()
{
test d;
test b = d;
test e(b);
getchar();
return 0;
}
When I run it I see
i am in a copy constructor
i am in a copy constructor
So that means that the overloaded equal operator function is not
called.

First, you don't have an overloaded equals operator; that would
be operator==. What you have overloaded is the assignment
operator. And you have no assignment *operator* in your
program:

test b = d ;

is a definition, and the '=' sign here is *not* an operator, but
simply punctuation. (Roughly speaking, an operator is something
in an expression, and the expression here only starts after the
= sign.) Semantically, if the expression has the same type as
the object being initialized (as is the case here), this
statement is exactly the equivalent of:

test b( d ) ;

, if the expression has another type, the statement would be
more or less the equivalent of:

test b( test( d ) ) ;

except that the conversion will be implicit (which limits
somewhat the conversions which will be considered: no explicit,
etc.)
Why is that?

Because the language says so.
Is this compiler dependent?

Not at all.
I am using g++. Is there
any document to describe the underline mechanic?

The standard, but that's pretty unreadable. Other than that,
any good introductory C++ text should explain declaration
syntax.
 
M

Markus Schoder

Just a nit, but the test for self assignment isn't really necessary.
Neither here, nor in general.

Are you saying it _never_ serves a purpose? Now that would be a bold
statement to make.

I have used it frequently in classes that manage their own dynamic memory
and so did the standard library implementers of the compiler I use. What
are we missing?
 
M

Markus Schoder

the syntax is confusing.
actually it's equivalent to

test b(d);

These are not equivalent. Yours is direct-initialization the OP's is copy-
initialization. Both are subtly different. What is true is that they both
do not invoke the copy-assignment operator.
 
J

James Kanze

Are you saying it _never_ serves a purpose? Now that would be a bold
statement to make.

Never, I don't know. But everytime I've seen it used, it's
either been a pessimization (because it adds an extra test in
the far more frequent case), or the assignment operator had a
bug, and didn't work correctly
I have used it frequently in classes that manage their own
dynamic memory

I don't see where it helps anything here. The usual solution:

MyClass&
MyClass::eek:perator=( MyClass const& other )
{
Internal* tmp = new Internal( *other.ptr ) ;
delete ptr ;
ptr = tmp ;
return *this ;
}

does quite well without it, and for anything more complicated,
you'd probably want to use the swap idiom anyway.
and so did the standard library implementers of the compiler I use.

Which part? I've not looked, but I don't see anywhere off hand
where it would be appropriate.
What are we missing?

I don't know, since you don't actually give an example of when
it might be necessary.
 
J

James Kanze

These are not equivalent. Yours is direct-initialization the
OP's is copy- initialization. Both are subtly different.

Except when the initialization expression has the same type as
the variable being defined. Then they are the same.
What is true is that they both do not invoke the
copy-assignment operator.

Given that there is no assignment operator in either, it's not
surprising.
 
G

Guest

Are you saying it _never_ serves a purpose? Now that would be a bold
statement to make.

I have used it frequently in classes that manage their own dynamic memory
and so did the standard library implementers of the compiler I use. What
are we missing?

Just that "in general" is not the same as "always", or put another way,
he did not say that it _never_ serves a purpose, just that in the
general case it does not. The validity of that statement I leave for
others to discuss.
 
M

Markus Schoder

Never, I don't know. But everytime I've seen it used, it's either been
a pessimization (because it adds an extra test in the far more frequent
case), or the assignment operator had a bug, and didn't work correctly


I don't see where it helps anything here. The usual solution:

MyClass&
MyClass::eek:perator=( MyClass const& other ) {
Internal* tmp = new Internal( *other.ptr ) ;
delete ptr ;
ptr = tmp ;
return *this ;
}

does quite well without it, and for anything more complicated, you'd
probably want to use the swap idiom anyway.

Using the swap idiom will easily be slower in non-trivial cases than an
extra check so one would not want to use it unless needed for exception
safety.
Which part? I've not looked, but I don't see anywhere off hand where it
would be appropriate.

vector operator= tries hard to avoid reallocation and therefore uses
explicit destructor calls and reuses the allocated memory if possible. I
cannot see how this optimization would be possible without a self
assignment check.

Anyway since the `in general' was meant in the colloquial and not the
mathematical sense I have no issues with it.
 
J

James Kanze

Using the swap idiom will easily be slower in non-trivial cases than an
extra check so one would not want to use it unless needed for exception
safety.

I'm not sure I understand. If you have nothing which can cause
an exception, then just assigning the elements, one after the
other, is the obvious idiom, and doesn't require a self
assignment check. If you have something which can cause an
exception (e.g. any dynamic allocation), then you have to ensure
that the object is at least destructable any time an exception
might occur; otherwise it is not usable. For objects more
complicated than the above, the swap idiom is the easiest way to
do so (provided all the base classes and members collaborate),
and the additional overhead is negligeable.
vector operator= tries hard to avoid reallocation and therefore uses
explicit destructor calls and reuses the allocated memory if possible. I
cannot see how this optimization would be possible without a self
assignment check.

The standard does impose some strange requirements. The formal
semantics of "assign" are defined as "erase" followed by
"insert", which would make self-assignment undefined behavior
(although I doubt that that was the intent). It also means
destruction, then construction. Personally, what I'd normally
expect (but I'm not sure that it's legal) would be to use this
algorithm literally only if the capacity needed to be extended,
otherwise, assign the common elements, then either destruct the
extras (if the old vector is longer than the new) or copy
construct them (if the old vector is shorter than the new), on
the grounds that assignment may be faster than
destruct/construct (and intuitively seems more what one would
expect, particularly if the vectors were the same size).
Anyway since the `in general' was meant in the colloquial and
not the mathematical sense I have no issues with it.

Quite. I'm sure that there are exceptions. The main reason I
added it is because it is often symptomatic of constructors
which don't work in case of an exception, particularly where
dynamic memory is involved (since allocation can always raise an
exception).
 
M

Markus Schoder

I'm not sure I understand. If you have nothing which can cause an
exception, then just assigning the elements, one after the other, is the
obvious idiom, and doesn't require a self assignment check.

Vector or more generally classes that can use bulk copying in copy-
assignment would be examples (see below).
The standard does impose some strange requirements. The formal
semantics of "assign" are defined as "erase" followed by "insert", which
would make self-assignment undefined behavior (although I doubt that
that was the intent). It also means destruction, then construction.
Personally, what I'd normally expect (but I'm not sure that it's legal)
would be to use this algorithm literally only if the capacity needed to
be extended, otherwise, assign the common elements, then either destruct
the extras (if the old vector is longer than the new) or copy construct
them (if the old vector is shorter than the new), on the grounds that
assignment may be faster than destruct/construct (and intuitively seems
more what one would expect, particularly if the vectors were the same
size).

Actually that is what the vector implementation does -- I did not read it
quite correctly. The need for the self-assignment check stems probably
from the fact that it uses std::copy for the element assignment and
std::copy does not allow this kind of overlapping ranges.
 

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,965
Messages
2,570,148
Members
46,710
Latest member
FredricRen

Latest Threads

Top