2

I want to ask a question about copy reference operators.

I have the following class named Mystring and I have a copy reference operator for it, which works.

#ifndef _MY_STRING_
#define _MY_STRING_

class Mystring
{
private:
    char *str; // pointer to a char[] that holds a c-style string
public:
    Mystring(); // no args
    Mystring(const char *s); // overloaded
    Mystring(const Mystring &source); // copy
    ~Mystring(); // destructor

    Mystring &operator=(const Mystring &rhs);// overloaded copy assignment operator

    void display() const; // getters
    int get_length() const;
    const char *get_str() const; // pointer is returned

};

#endif // _MY_STRING_

and this is the copy reference operator function:

// Overloaded assignment copy operator
Mystring &Mystring::operator = (const Mystring &rhs) {
    std::cout << "Copy assignment" << std::endl;
    if (this == &rhs) // check the pointer is on the same address of rhs i.e. & = reference operator
        return *this; // returns the reference
    delete [] this->str;
    str = new char [std::strlen(rhs.str) + 1];
    std::strcpy(this->str, rhs.str);
    return *this;
}

I'm a beginner in C++ so this is confusing but I'll try to describe what happens.

I'm aware that there is a this operator, which acts as a pointer. When dereferenced, it allows us to work with the object itself.

From the first line

Mystring &Mystring::operator = (const Mystring &rhs)

I can see that I will have an operator function that returns a reference, as the & operator exists in the declaration.

However, at the end of the if statement and the overall function, we state

return *this

although if we are dereferencing this, we're returning the object and not the reference as per my explanation above.

Microsoft c++ documentation also states

The expression *this is commonly used to return the current object from a member function:

To clarify, this is a pointer to a current object so *this and then returning it should mean that i'm returning the object, not another reference.

What mistake am I making in my understanding of this code?

bodn19888
  • 167
  • 10
  • `#define _MY_STRING_` That identifier is reserved to the language implementation. By defining it, your program will have undefined behaviour. You should use another header guard. – eerorika Aug 12 '20 at 18:43
  • `*this` and all named variables can bind to references because they are l-values(~named) references to their objects . Also there are multiple meanings of `&` - one is taking address of a variable, another is being a reference type, they are not exactly the same. So `int& var` and `*ptr` are not opposite operations. `int var; int*ptr =&var` and `*ptr` would be. – Quimby Aug 12 '20 at 18:47
  • @Quimby I understand, but my confusion is that `return *this` implies that the object itself will be returned, however the code seems to work by stating that a reference to the current object will be returned, and I don't understand how that works. `this` is a pointer to a current object so `*this` and then returning it should mean that i'm returning the object, not another reference. I hope that makes my original point clearer. – bodn19888 Aug 12 '20 at 18:50
  • @bodn19888 Yes, it boils down to [value categories](https://en.cppreference.com/w/cpp/language/value_category) of expressions, which is not really a beginner-friendly topic. But `*this` is itself a named reference. That is why your copy constructor from string can do stuff like `std::string str; Mystring s(str)`. Here `str` got bound to reference too. It has to, how else would you assign to the references in the first place. There is no copy of `str`, just the reference. This is exactly the same, but the name of the object is `*this` and it can too, be bound to a reference. – Quimby Aug 12 '20 at 18:55
  • `int var;`, `var` means I am a name for the object I store. `int& r = var` means that `r` will be just another name for the same object. `int var2 = var` means: I will copy the object referenced by `var` and will be a new name to this new object. `*this` is also just a name, do not worry about that `this` is a pointer. You can do `Mystring s = *this` and a copy will be made which will be named `s`. Or you can do `Mystring& r = *this` and the exact same thing as with `int&` will happen, `r` will reference the same object as `*this` i.e. gives the object a new name. – Quimby Aug 12 '20 at 19:00
  • oh so you return the object in the first place and then create the reference to it after it is returned to the name on the left hand side of the equals sign? @Quimby – bodn19888 Aug 12 '20 at 19:04
  • @bodn19888 Nope, you always return a reference to it. No copy is made in `return *this`. Sorry, I am not really great at explaining this very well :D Your code is equivalent to `Mystring& returned_value = *this;` and this is the same as `int x; int& ref = x;` Only the objects named `*this` and `x` exist. `returned_value` is just a new name given to the same object. `ref` is also just a new name for the same object. All variable names can be bound to a reference, in that case no copy is made because the expression `x` itself is a l-value reference i.e. a name for the object in the memory. – Quimby Aug 12 '20 at 19:09
  • Yeah that's what i meant. in my situation, if I have a `Mystring` object named `obj1` and I do `obj2 = obj1`, what I'm doing is `return *this` in the function which then does `Mystring & obj2 = *this` - this is what i think is happening and I wanted to clarify if this is a case. I'm aware also of L-values and R-values where L-values have a name and memory address and R-values do not, unless I'm heavily mistaken. It's just the C++ syntax is hard to explain and requires self-working out. – bodn19888 Aug 12 '20 at 19:17
  • @bodn19888 Yes, in that case you are correct. `Mystring & obj2 = *this` is exactly what is happening. Well, if you are, you don't have to call yourself a beginner anymore :) ( at least by my standards) – Quimby Aug 12 '20 at 19:20
  • @Quimby do you have a good reference that explains all the above points because the C++ articles that I have read contain too much jargon and don't simplify the concepts as well as we have done? I'm going to write my own answer anyway later once you reply! and thank you by the way i try my best!! – bodn19888 Aug 12 '20 at 19:27
  • @bodn19888 You are most welcome, but no, sorry. I kinda learnt from my failures (=experience) and books. There is very good [curated book list](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) if you are interested. My advice is to just use C++ and look stuff up if you are not sure about anything. Asking here, just as you've done, is always an option, but sometimes the community is kinda harsh towards beginners questions :( – Quimby Aug 12 '20 at 19:32
  • @Quimby I do my best to explain my line of thoughts although my recent experience on SO before this question suggests a lot of hostility and an unusual desire for more complex questions, which seems odd. Thanks very much though anyway! – bodn19888 Aug 12 '20 at 19:35
  • @bodn19888 Well, I get it, if you see copy pasted problem with 0 effort for the hundredth time, you stop reading non-interesting questions. I too like complex questions but I try to judge the question by the effort the user made to ask it, not so much its content. – Quimby Aug 12 '20 at 19:38

2 Answers2

1

In C++ there are expressions whose evaluation just determines the identity of an object. They are called glvalue expressions. This is the case of the expression *this. this hold a value that represents an address in memory and the expression *this evaluates to the identity of the object that is at that address. This may be strange to call this an evaluation, this is just a designation: *this designates the object that is at the address hold by this.

A function that returns a reference, when called result in a glvalue: it just designates an object. In the case of the operator = this object is the one designated by the expression in the return statement *this.

Oliv
  • 17,610
  • 1
  • 29
  • 72
0

To clarify, this is a pointer to a current object so *this and then returning it should mean that i'm returning the object, not another reference.

You are correct, this is the pointer and *this is the object the pointer points to.

Take a look, however, on how you deal with references. For example consider passing a value to a function by reference. It is done in a following way:

void foo(char &param) {
  // do something
}

int main(int argc, char **argv) {

    int x = 5;
    
    foo(x);
    
    return 0;
}

Note that the variable x is passed by reference but there is no & or * needed to indicate that to the compiler. This is because the compiler can figure it out by itself. This is also why you return *this and it is understood as reference.