Help please!!!!

Pages: 12
In this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// Ex8_05.cpp
// Overloaded assignment operator working well
#include <iostream>
#include <cstring>
using std::cout;
using std::endl;
        
class CMessage
{
  private:
    char* pmessage;                    // Pointer to object text string
        
  public:
    // Function to display a message
    void ShowIt() const
    {
      cout << endl << pmessage;
    }
        
    //Function to reset a message to *
    void Reset()
    {
      char* temp = pmessage;
      while(*temp)
        *(temp++) = '*';
    }

    // Overloaded assignment operator for CMessage objects
    CMessage operator=(const CMessage& aMess)
    {
      if(this != &aMess)                   // Check addresses are not equal
      {        
        // Release memory for 1st operand
        delete[] pmessage;
        pmessage = new char[strlen(aMess.pmessage) + 1];
        
        // Copy 2nd operand string to 1st
        strcpy_s(this->pmessage, strlen(aMess.pmessage)+1, aMess.pmessage);
      }
      // Return a reference to 1st operand
      return *this;
    }
        
    // Constructor definition
    CMessage(const char* text = "Default message")
    {
      pmessage = new char[strlen(text) + 1];       // Allocate space for text
      strcpy_s(pmessage, strlen(text)+1, text);    // Copy text to new memory
    }
        
    // Copy constructor definition
    CMessage(const CMessage& aMess)
    {
      size_t len = strlen(aMess.pmessage)+1;
      pmessage = new char[len];
      strcpy_s(pmessage, len, aMess.pmessage);
    }
        
    // Destructor to free memory allocated by new
    ~CMessage()
    {
      cout << "Destructor called."      // Just to track what happens
           << endl;
      delete[] pmessage;                // Free memory assigned to pointer
    }
};
        
int main()
{
  CMessage motto1("The devil takes care of his own");
  CMessage motto2;
  CMessage motto3;

  cout << "motto2 contains - ";
  motto2.ShowIt();
  cout << endl;

  (motto1 = motto2) = motto3;

  cout << "motto2 contains - ";
  motto2.ShowIt();
  cout << endl;

  motto1.Reset();                      // Setting motto1 to * doesn't
                                       // affect motto2
  cout << "motto1 now contains - ";
  motto1.ShowIt();
  cout << endl;

  cout << "motto2 still contains - ";
  motto2.ShowIt();
  cout << endl;

  return 0;
  }


One line 78 shouldn't there be a error since a rvalue is returned on the left side of the assignment operator? Atleast thats what my book says. I understand that this will point to the same object when you return it so it isn't a rvalue but why does my book say this then?

Book:

"You can fix this with your own assignment operator function, which I will assume is defined within the class definition. Here’s a first stab at it, which I’ll warn you now is not sufficient for proper operation:

1
2
3
4
5
6
7
8
// Overloaded assignment operator for CMessage objects CMessage& operator=(const CMessage& aMess)
{
// Release memory for 1st operand delete[]  pmessage;
pmessage  =  new  char[strlen(aMess.pmessage)  +  1];
// Copy 2nd operand string to 1st
strcpy_s(this->pmessage,  strlen(aMess.pmessage)  +  1,  aMess.pmessage);
return *this;
}


An assignment might seem very simple, but there’s a couple of subtleties that need further investigation. First of all, note that you return a reference from the assignment operator function. It may not be immediately apparent why this is so — after all, the function does complete the assignment operation entirely, and the object on the right of the assignment will be copied to that on the left. Superficially, this would suggest that you don’t need to return anything, but you need to consider in a little more depth how the operator might be used.

You might need to use the result of an assignment operation on the right-hand side of another assignment. Consider this statement:

motto1 = motto2 = motto3;

The assignment operator is right-associative so the assignment of motto3 to motto2 will be carried out first. The statement will translate into the following:

motto1 = (motto2.operator=(motto3));

The result of the operator function call is on the right of the equals sign, so the statement will finally become this:

motto1.operator=(motto2.operator=(motto3));

If this is to work, you certainly have to return something from the operator=() function. The function call between the parentheses must return an object that can be used as the argument to the other operator=() function call. In this case, a return type of either CMessage or CMessage& would do it, so a reference is not mandatory for this situation, but you must at least return a CMessage object.

However, consider the following example:

(motto1 = motto2) = motto3;

This is perfectly legitimate code — the parentheses serve to make sure the leftmost assignment is carried out first. This translates into the following statement:

(motto1.operator=(motto2)) = motto3;

When you express the remaining assignment operation as the explicit overloaded function call, this ultimately becomes:

(motto1.operator=(motto2)).operator=(motto3);

Now, you have a situation where the object returned from the operator=() function is used to call the operator=() function. If the return type is just CMessage, this will not be legal because a temporary copy of the original object is actually returned so it will be an rvalue, and the compiler will not allow a member function call using an rvalue. The only way to ensure this will compile and work correctly is to return a reference, which is an lvalue. The only possible return type if you want to allow fully flexible use of the assignment operator with your class objects is CMessage&."

Can anyone please help? Thanks :D or is it that my author is just really dumb?
Last edited on
> One line 78 shouldn't there be a error since a rvalue is returned on the left side of the assignment operator?
(motto1 = motto2) = motto3; //CMessage operator=(const CMessage& aMess)
No error. Because you return a non-const object you can send it any message
http://courses.cms.caltech.edu/cs11/material/cpp/donnie/cpp-ops.html (binary operators)

> and the compiler will not allow a member function call using an rvalue
that's wrong.

If you return a value instead of a reference, then the assignment is done to a temporary.
But it returns a temporary or no?

And also I can deduce my author is dumb from this right?
> But it returns a temporary or no?
CMessage operator=
Yes, it does.

> I understand that this will point to the same object when you return it
Nope, it's a copy.
Why is it a copy? Isnt the this pointer pointing to the object motto1?

So shouldnt it just return motto1?
Last edited on
Look at the return type.
1
2
3
4
5
    CMessage operator=(const CMessage& aMess)
    {
      // Return a reference copy of the 1st operand
      return *this;
    }

You are asking to return an object, so return *this; will call the copy constructor
ne555,

Would you mind my PMing you to look at something miniscule? I will post it to the board for reference after I submit it later this week. I would greatly appreciate it.

Thanks.
So wait, all values returned from functions are rvalues or copies unless its returning a reference?
Last edited on
Or is it only for objects when you return them it is a copy?
Any object, save arrays, when passed via a return from a function or as a parameter to a function are passed by value (are copied) unless otherwise indicated (by reference.)
Last edited on
But why?
Last edited on
Also only arrays are not copied right, cause the array name is a pointer? And everything else is? Like ints, longs, doubles?
But why?

Because that's the default method of passing objects.

Also only arrays are not copied right, cause the array name is a pointer? And everything else is? Like ints, longs, doubles?

Correct.
Oh ok Thanks cire you're always a great help :D

Thanks ne555 too :D
Also quoting ne55

"If you return a value instead of a reference, then the assignment is done to a temporary."

How exactly does that work? I thought you can't assign to rvalues cause it is dangerous?
Last edited on
¿dangerous how? if it crashes when acting on a temporary, then your code is broken.
1
2
3
4
5
6
class foo{};

int main(){
   foo bar;
   foo() = bar; //compiles
}
If everything that were dangerous in C++ were disallowed, there wouldn't be much left. Returning a const object would disallow the assignment to the temporary (because it would be const.)

Of course, returning a reference would preserve the usual expected semantics of operator= and should be preferred where possible.
Last edited on
But isnt rvalues on the left of a assignment completely disallowed? Why does it work here?

I am really confused here?
ne555

How does that work O.O

How can you assign the class itself a object? o.O
Pages: 12