assignment operator overload error??

Discussion in 'C++' started by Sean, Sep 29, 2005.

  1. Sean

    Sean Guest

    Can someone help me see why the following "operator=" overloading
    doesn't work under g++? and the error message is copied here. I see no
    reason the compiler complain this. Thanks,

    [bash]$ g++ copyconstructor1.cpp
    #copyconstructor1.cpp: In function `int main()':
    #copyconstructor1.cpp:86: no match for `sample& = sample' operator
    #copyconstructor1.cpp:53: candidates are: sample sample::eek:perator=(sample&)

    =========================================
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    using namespace std;

    class sample {
    char *s;
    public:
    sample(); // normal constructor
    sample(const sample &ob); // copy constructor
    ~sample( ) { if(s) delete [] s; cout << "Freeing s\n"; }
    void show() { cout << s << "\n"; }
    void set(char *str);
    sample operator=(sample &ob); // overload assignment
    };

    // Normal constructor.
    sample::sample()
    {
    s = new char('\0'); // s points to a null string.
    if(!s) {
    cout << "Allocation error\n";
    exit(1); // exit program if out of memory
    }
    }

    // Copy constructor.
    sample::sample(const sample &ob)
    {
    s = new char[strlen(ob.s)+1];
    if(!s) {
    cout << "Allocation error\n";
    exit(1); // exit program if out of memory
    }
    strcpy(s, ob.s);
    }

    // Load a string.
    void sample::set(char *str)
    {
    s = new char[strlen(str)+1];
    if(!s) {
    cout << "Allocation error\n";
    exit(1); // exit program if out of memory
    }
    strcpy(s, str);
    }


    sample sample::eek:perator=(sample &ob)
    {
    /* If the target string is not large enough
    then allocate a new string. */
    if(strlen(ob.s) > strlen(s)) {
    delete [] s;
    s = new char[strlen(ob.s)+1];
    if(!s) {
    cout << "Allocation error\n";
    exit(1); // exit program if out of memory
    }
    }
    strcpy(s, ob.s);
    return *this;
    }

    // Return an object of type sample.
    sample input()
    {
    char instr[80];
    sample str;

    cout << "Enter a string: ";
    cin >> instr;

    str.set(instr);
    return str;
    }

    int main()
    {
    sample ob;

    ob = input(); // This doesn't compile under g++
    ob.show();

    return 0;
    }
     
    Sean, Sep 29, 2005
    #1
    1. Advertising

  2. Sean wrote:
    > Can someone help me see why the following "operator=" overloading
    > doesn't work under g++? and the error message is copied here. I see no
    > reason the compiler complain this. Thanks,
    >


    A few errors, see comments below.

    > [bash]$ g++ copyconstructor1.cpp
    > #copyconstructor1.cpp: In function `int main()':
    > #copyconstructor1.cpp:86: no match for `sample& = sample' operator
    > #copyconstructor1.cpp:53: candidates are: sample sample::eek:perator=(sample&)
    >
    > =========================================
    > #include <iostream>
    > #include <cstring>
    > #include <cstdlib>
    > using namespace std;
    >
    > class sample {
    > char *s;
    > public:
    > sample(); // normal constructor
    > sample(const sample &ob); // copy constructor
    > ~sample( ) { if(s) delete [] s; cout << "Freeing s\n"; }
    > void show() { cout << s << "\n"; }
    > void set(char *str);
    > sample operator=(sample &ob); // overload assignment


    Should be

    sample operator=(const sample &ob); // overload assignment

    You program does not compile because you wrote the assignment operator
    with a non-const reference instead of a const reference.

    There is a rule in C++ that you cannot bind a temporary to a non-const
    reference, so assignment operators and copy constructors (and most other
    things) should be writen with const references if possible.

    > };
    >
    > // Normal constructor.
    > sample::sample()
    > {
    > s = new char('\0'); // s points to a null string.


    This is wrong. You cannot mixup allocations with new and new[], because
    you must free new with delete and new[] with delete[].

    This is correct

    s = new char[1];
    s[0] = '\0';

    > if(!s) {


    This is wrong, new does not return NULL if it fails, instead it throws
    an exeption.

    > cout << "Allocation error\n";
    > exit(1); // exit program if out of memory
    > }
    > }
    >
    > // Copy constructor.
    > sample::sample(const sample &ob)
    > {
    > s = new char[strlen(ob.s)+1];
    > if(!s) {


    Again, new never returns NULL.

    > cout << "Allocation error\n";
    > exit(1); // exit program if out of memory
    > }
    > strcpy(s, ob.s);
    > }
    >
    > // Load a string.
    > void sample::set(char *str)
    > {
    > s = new char[strlen(str)+1];
    > if(!s) {
    > cout << "Allocation error\n";
    > exit(1); // exit program if out of memory
    > }
    > strcpy(s, str);
    > }


    This function is ill conceived. It also leaks memory becaise the string
    will already have some memory allocated which you don't free.

    You should rewrite this as a constructor

    sample::sample(const char* str)
    {
    s = new char[strlen(str)+1];
    strcpy(s, str);
    }

    >
    >
    > sample sample::eek:perator=(sample &ob)
    > {
    > /* If the target string is not large enough
    > then allocate a new string. */
    > if(strlen(ob.s) > strlen(s)) {
    > delete [] s;
    > s = new char[strlen(ob.s)+1];
    > if(!s) {


    Again.

    > cout << "Allocation error\n";
    > exit(1); // exit program if out of memory
    > }
    > }
    > strcpy(s, ob.s);
    > return *this;
    > }
    >
    > // Return an object of type sample.
    > sample input()
    > {
    > char instr[80];
    > sample str;
    >
    > cout << "Enter a string: ";
    > cin >> instr;
    >
    > str.set(instr);
    > return str;
    > }


    Now if you rewrite sample::set as a constructor this function becomes
    really easy

    sample int()
    {
    char instr[80];
    cout << "Enter a string: ";
    cin >> instr;
    return instr;
    }

    The compiler will create a sample object from the instr array using the
    constructor I advised you to write above.

    >
    > int main()
    > {
    > sample ob;
    >
    > ob = input(); // This doesn't compile under g++
    > ob.show();
    >
    > return 0;
    > }


    Above all you need to learn about const.

    john
     
    John Harrison, Sep 29, 2005
    #2
    1. Advertising

  3. Sean

    David White Guest

    Sean wrote:
    > Can someone help me see why the following "operator=" overloading
    > doesn't work under g++? and the error message is copied here. I see no
    > reason the compiler complain this. Thanks,
    >
    > [bash]$ g++ copyconstructor1.cpp
    > #copyconstructor1.cpp: In function `int main()':
    > #copyconstructor1.cpp:86: no match for `sample& = sample' operator
    > #copyconstructor1.cpp:53: candidates are: sample
    > sample::eek:perator=(sample&)
    >
    > =========================================
    > #include <iostream>
    > #include <cstring>
    > #include <cstdlib>
    > using namespace std;
    >
    > class sample {
    > char *s;
    > public:
    > sample(); // normal constructor
    > sample(const sample &ob); // copy constructor
    > ~sample( ) { if(s) delete [] s; cout << "Freeing s\n"; }
    > void show() { cout << s << "\n"; }
    > void set(char *str);
    > sample operator=(sample &ob); // overload assignment


    It's unusual for operator= to return a copy of itself, which you are doing,
    but I doubt that that's your problem. It's more likely that the reference
    argument is not const. Try making this your operator=:
    sample &operator=(const sample &ob);

    > };


    [snip]

    > int main()
    > {
    > sample ob;
    >
    > ob = input(); // This doesn't compile under g++


    The compiler probably doesn't like passing the temporary returned by input()
    as a non-const reference to the assignment operator. I actually thought the
    standard prohibited this, but neither VC++ 6.0 nor VS .NET 2003 is
    complaining about it.

    > ob.show();
    >
    > return 0;
    > }


    DW
     
    David White, Sep 29, 2005
    #3
  4. >
    > The compiler probably doesn't like passing the temporary returned by input()
    > as a non-const reference to the assignment operator. I actually thought the
    > standard prohibited this, but neither VC++ 6.0 nor VS .NET 2003 is
    > complaining about it.


    The standard does prevent it. With those compilers you can get the
    correct behaviour if you turn on 'disable language extensions', the /Za
    options.

    john
     
    John Harrison, Sep 29, 2005
    #4
  5. Sean

    David White Guest

    "John Harrison" <> wrote in message
    news:pJM_e.3263$...
    > >
    > > The compiler probably doesn't like passing the temporary returned by

    input()
    > > as a non-const reference to the assignment operator. I actually thought

    the
    > > standard prohibited this, but neither VC++ 6.0 nor VS .NET 2003 is
    > > complaining about it.

    >
    > The standard does prevent it. With those compilers you can get the
    > correct behaviour if you turn on 'disable language extensions', the /Za
    > options.


    Well, that's ridiculous. You should have to _enable_ the extensions with a
    switch, not disable. Thanks.

    DW
     
    David White, Sep 29, 2005
    #5
  6. David White wrote:
    > "John Harrison" <> wrote in message
    > news:pJM_e.3263$...
    >
    >>>The compiler probably doesn't like passing the temporary returned by

    >
    > input()
    >
    >>>as a non-const reference to the assignment operator. I actually thought

    >
    > the
    >
    >>>standard prohibited this, but neither VC++ 6.0 nor VS .NET 2003 is
    >>>complaining about it.

    >>
    >>The standard does prevent it. With those compilers you can get the
    >>correct behaviour if you turn on 'disable language extensions', the /Za
    >>options.

    >
    >
    > Well, that's ridiculous. You should have to _enable_ the extensions with a
    > switch, not disable. Thanks.
    >
    > DW
    >


    Backwards compatibility I think. VC++ 6 could not compile <windows.h>
    without 'language extensions'. Don't know if that is still the case but
    I wouldn't be surprised.

    john
     
    John Harrison, Sep 29, 2005
    #6
  7. Sean

    Dave Guest

    I am studying C++, currently learning to overload the assignment
    operator. My text book (by D.S. Malik) teaches that the assignment
    operator overload function returns a const reference, but it does not
    explain why. In trying to understand this, I see that an address is
    passed, and that address is not being changed, but I expect the
    overloaded assignment function to change the data referenced by that
    address. So I am confused how it can be const.

    While goggling for an explaination, I found a recent post where you
    helped someone who did not use a const reference in an assignment
    overload prototype statement. Could you help me understand what "bind
    a temporary to a non-const reference" means?

    Dave


    > > sample operator=(sample &ob); // overload assignment

    >
    > Should be
    >
    > sample operator=(const sample &ob); // overload assignment
    >
    > You program does not compile because you wrote the assignment operator
    > with a non-const reference instead of a const reference.
    >
    > There is a rule in C++ that you cannot bind a temporary to a non-const
    > reference, so assignment operators and copy constructors (and most other
    > things) should be writen with const references if possible.
    >
    > > };
    > >

    ... snip

    > john
     
    Dave, Oct 6, 2005
    #7
  8. Sean

    Kai-Uwe Bux Guest

    Dave wrote:

    > I am studying C++, currently learning to overload the assignment
    > operator. My text book (by D.S. Malik) teaches that the assignment
    > operator overload function returns a const reference, but it does not
    > explain why.


    If the book really makes that claim, it cannot give a reason because the
    claim is false:

    struct IntWrapper {

    int i;

    IntWrapper ( int ii = 0 )
    : i ( ii )
    {}

    IntWrapper & inc ( void ) {
    ++ i;
    return ( *this );
    }

    IntWrapper & operator= ( IntWrapper const & other ) {
    i = other.i;
    return ( *this );
    }

    }; // IntWrapper;

    #include <iostream>

    int main ( void ) {
    IntWrapper a ( 5 );
    IntWrapper b ( 3 );
    ( b = a ).inc().inc();
    std::cout << b.i << '\n';
    }



    It also fails for the assignment operator that is automatically provided by
    the compiler:


    struct IntWrapper {

    int i;

    IntWrapper ( int ii = 0 )
    : i ( ii )
    {}

    IntWrapper & inc ( void ) {
    ++ i;
    return ( *this );
    }

    }; // IntWrapper;

    #include <iostream>

    int main ( void ) {
    IntWrapper a ( 5 );
    IntWrapper b ( 3 );
    ( b = a ).inc().inc();
    std::cout << b.i << '\n';
    }


    > In trying to understand this, I see that an address is
    > passed, and that address is not being changed, but I expect the
    > overloaded assignment function to change the data referenced by that
    > address. So I am confused how it can be const.
    >
    > While goggling for an explaination, I found a recent post where you
    > helped someone who did not use a const reference in an assignment
    > overload prototype statement. Could you help me understand what "bind
    > a temporary to a non-const reference" means?


    You are confusing three different things:

    a) non-constness of the return type.
    (it's not necessary to make the return type const)

    b) non-constness of the operator= method.
    (it usually is necessary to make this method non-const.)

    c) constness of the argument type.
    (it is usually a good idea to have the argument be const.)
    [see auto_ptr<T> for a case where the argument is non-const.]


    >> > sample operator=(sample &ob); // overload assignment

    >>
    >> Should be
    >>
    >> sample operator=(const sample &ob); // overload assignment
    >>
    >> You program does not compile because you wrote the assignment operator
    >> with a non-const reference instead of a const reference.
    >>
    >> There is a rule in C++ that you cannot bind a temporary to a non-const
    >> reference, so assignment operators and copy constructors (and most other
    >> things) should be writen with const references if possible.


    This quote discusses item (c) from above. Neither (a) nor (b) are at issue
    here.


    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Oct 6, 2005
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Piotre Ugrumov
    Replies:
    3
    Views:
    384
    Nick Hounsome
    Jan 25, 2004
  2. G Patel

    comma operator and assignment operator

    G Patel, Feb 7, 2005, in forum: C Programming
    Replies:
    4
    Views:
    506
    Barry Schwarz
    Feb 8, 2005
  3. Chris
    Replies:
    34
    Views:
    1,567
  4. Hicham Mouline
    Replies:
    2
    Views:
    724
    Juha Nieminen
    Sep 1, 2009
  5. Ying-Chieh Liao

    function overload (not operator overload)

    Ying-Chieh Liao, Oct 11, 2004, in forum: Perl Misc
    Replies:
    3
    Views:
    274
    Sherm Pendley
    Oct 11, 2004
Loading...

Share This Page