Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7673895
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 31, 20262026-05-31T16:37:02+00:00 2026-05-31T16:37:02+00:00

Now that it’s answered: Don’t bother reading this question, it’s a bit lengthy and

  • 0

Now that it’s answered: Don’t bother reading this question, it’s a bit lengthy and probably not worth your time. There were bugs in my code, and that was the reason why the move constructor wasn’t called. Check the answers for details. Keep in mind that RVO and NRVO (Named Return Value Optimization) might account for the calls not happening as you expect.


I expect the move ctor to be called for this line, but the copy ctor is called instead:

Ding d3 = d1 + d2;

The Ding class has a user-defined move ctor and on operator+ overload. The reason I expect the move ctor to be called is that the operator+ returns a temporary object, an rvalue reference, so the move optimization could happen.

Everything I’m writing here might be wrong as I’m a C++ beginner. Here’s the code:

// Copied and modified code from here: https://stackoverflow.com/a/3109981
#include <iostream>
#include <cstring>

struct Ding {
    char* data;

    Ding(const char* p) {
        std::cout << " ctor for: " << p << "\n";
        size_t size = strlen(p) + 1;
        data = new char[size];
        memcpy(data, p, size);
    }

    ~Ding() {
        std::cout << " dtor for: " << data << "\n";
        delete[] data;
    }

    Ding(const Ding& that) {
        std::cout << " copy for: " << that.data << "\n";
        size_t size = strlen(that.data) + 1;
        data = new char[size];
        memcpy(data, that.data, size);
    }

    Ding(Ding&& that) {
        std::cout << " MOVE for: " << that.data << "\n";
        data = that.data;
        that.data = nullptr;
    }

    Ding& operator=(Ding that) {
        std::cout << " assignment: " << that.data << "\n";
        std::swap(data, that.data);
        return *this;
    }

    Ding& operator+(const Ding that) const {
        std::cout << " plus for: " << that.data << "\n";
        size_t len_this = strlen(this->data);
        size_t len_that = strlen(that.data);
        char * tmp = new char[len_this + len_that + 1];
        memcpy( tmp,          this->data, len_this);
        memcpy(&tmp[len_this], that.data, len_that + 1);
        Ding * neu = new Ding(tmp);
        return *neu;
    }
};

void print(Ding d) {
    std::cout << "  (print): " << d.data << std::endl;
}

int main(void) {
    std::cout << "putting a Ding on the stack\n";
    Ding d1("jajaja");
    std::cout << "calling print routine\n";
    print(d1);
    std::cout << "putting a second Ding on the stack\n";
    Ding d2("nein");
//  std::cout << "calling print routine\n";
//  print(d2);
    std::cout << "Putting a third Ding on the stack, init from + op ...\n";
    std::cout << "... so expecting so see MOVE ctor used ...\n";
    Ding d3 = d1 + d2;
//  std::cout << "calling print routine\n";
//  print(d3);
    std::cout << "End of main, dtors being called ...\n";
}

The compiler invocations (on Win7) for VC2010 Express and MinGW (GCC 4.6) are as follows:

cl /nologo /W4 /EHsc /MD move-sem.cpp
g++ -std=c++0x move-sem.cpp -o move-gcc.exe

Both binaries produce the same output (sans order of destruction at end of program):

putting a Ding on the stack
 ctor for: jajaja
calling print routine
 copy for: jajaja
  (print): jajaja
 dtor for: jajaja
putting a second Ding on the stack
 ctor for: nein
Putting a third Ding on the stack, init from + op ...
... so expecting so see MOVE ctor used ...
 copy for: nein
 plus for: nein
 ctor for: jajajanein
 dtor for: nein
 copy for: jajajanein
End of main, dtors being called ...
 dtor for: jajajanein
 dtor for: nein
 dtor for: jajaja

To recall what the question was after this long text: Why isn’t the move constructor called for Ding d3 = d1 + d2;?

I’m aware that there are other questions as to why move ctors aren’t getting called but I cannot map their answers to this case.

  • Why doesn’t this C++0x code call the move constructor?
  • Why is this code trying to call the copy constructor?
  • Move constructor is not getting called in C++0x

Update

I changed the program as follows as per David Rodriguez’ comments:

--- move-sem.cpp.orig   2012-03-17 17:00:56.901570900 +0100
+++ move-sem.cpp        2012-03-17 17:01:14.016549800 +0100
@@ -36,15 +36,14 @@
                return *this;
        }

-       Ding& operator+(const Ding that) const {
+       Ding operator+(const Ding that) const {
                std::cout << " plus for: " << that.data << "\n";
                size_t len_this = strlen(this->data);
                size_t len_that = strlen(that.data);
                char * tmp = new char[len_this + len_that + 1];
                memcpy( tmp,          this->data, len_this);
                memcpy(&tmp[len_this], that.data, len_that + 1);
-               Ding * neu = new Ding(tmp);
-               return *neu;
+               return tmp;
        }
 };

I then recompiled the program using the compiler invocations mentioned above and got an output where one copy (copy for: jajajanein) was removed. I then tried the following line:

g++ -std=c++0x -fno-elide-constructors move-sem.cpp -o move-gcc.exe

And tata! Now I’m seeing the move ctor at work! … But I think there’s another error now, the output of that new move-gcc.exe doesn’t list the dtor invocations any more:

putting a Ding on the stack
 ctor for: jajaja
calling print routine
 copy for: jajaja
  (print): jajaja
 dtor for: jajaja
putting a second Ding on the stack
 ctor for: nein
Putting a third Ding on the stack, init from + op ...
... so expecting so see MOVE ctor used ...
 copy for: nein
 plus for: nein
 ctor for: jajajanein
 MOVE for: jajajanein
 dtor for:

Second Update

I replaced the bad operator+ with the following (possibly equally bad) code:

Ding& operator+=(const Ding & rhs) {
    std::cout << " op+= for: " << data << " and " << rhs.data << "\n";
    size_t len_this = strlen(this->data);
    size_t len_that = strlen(rhs.data);
    char * buf = new char[len_this + len_that + 1];
    memcpy( buf,         this->data, len_this);
    memcpy(&buf[len_this], rhs.data, len_that + 1);
    delete[] data;
    data = buf;
    return *this;
}

Ding operator+(const Ding & rhs) const {
    Ding temp(*this);
    temp += rhs;
    return temp;
}

I also removed the following line from the destructor, and it stopped the program from terminating abnormally:

std::cout << " dtor for: " << data << "\n";

The move constructor is now being called when compiling with MSVC and with g++ -std=c++0x -fno-elide-constructors.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-31T16:37:04+00:00Added an answer on May 31, 2026 at 4:37 pm
        Ding * neu = new Ding(tmp);
        return *neu;
    

    This is wrong. You are dynamically allocating a Ding and then forcing a copy of it. Because the Ding is dynamically allocated, you are leaking it, it’s lifetime extends beyond the return statement and the compiler cannot move from it. Note that you are not returning a temporary.

    Change that to:

        return Ding(tmp);
    

    Or even:

        return tmp;
    

    As your constructor taking a const char* is not explicit, the compiler will use it to create a new Ding object. In both cases, the lifetime of the temporary does not extend beyond the return statement and the compiler will move.

    (This answer assumes that you understand that the copy from the returned object to the d3 has been elided, if that is where you expected the move, then the compiler did something better: avoid the operation altogether).

    EDIT As DeadMG has written a canonical form but it includes errors I will follow up on that:

    There is much to say about operator overloading, but a common recommendation (the one I give and follow) is to implement operatorX= as a member function (it is an operation applied to the left hand side) and then implement operator+ as a free function in terms of the former. In C++11 that would be:

    class X {
       X& operator+=( X const & ); // we do not modify the rhs internally
    };
    X operator+( X lhs, X const & rhs ) {
      lhs += rhs;                  // reuse implementation
      return lhs;
    }
    

    Some things to note: operator+ is symmetric with respect to types as it is a free function. All implicit conversions that can happen on the right hand side are also available in the lhs. In your particular case, Ding is implicitly convertible from const char*, which means that by having a free function operator+ you can write:

    Ding d( "A" );
    const char* str = "B";
    d + d;     // no conversions
    d + str;   // conversion on the right hand side
    str + d;   // conversion on the left hand side
    

    By defining operator+= as a public member function you need to write a single implementation and that implementation can be reused, so you get two operators for the cost of one (and three extra lines of code that are trivial).

    Argument by value and return by value. This enables the compiler to elide the copy to the parameter if the argument is a temporary. As there is a move constructor, there will not be any internal copy either, the argument will be modified and moved to the return object. (This second copy cannot be elided).

    I wrote a bit more than this on operator overloading here some time ago… It does not explicitly deal with optimizations (moving) but there are other posts there that deal with the C++03 version of it. From that to C++11 features you should be able to fill in the blanks.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Now that android has a web store I was wondering how is this done
Now that I can make useful user controls in WPF (thanks to this stackoverflow
Now that Xcode is part of the App Store (I'm not a paid developer
Now that CSS3 includes styles to add rounded corners to images automatically, does this
Now that the canvas tag is starting to get hardware execration [acceleration - thanks
Now that Google App Engine natively supports Django 1.0, I updated with the following
Now that http://github.com/why/hpricot/wikis/home no longer exists.
Now that I know I can no longer communicate with Twitter mashups out there,
Now that I am using it for backend processing of csv files, and the
Now that I have decided upon Firebird , with the help of StackOverflow :),

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.