0

I have this piece of code

#include <iostream>
#include <vector>

using namespace std;

class ArrayWrapper {
    private:
        int *_p_vals;
        int _size;

    public:
        //default constructor
        ArrayWrapper () : _p_vals( new int[ 64 ] ) , _size( 64 ) {
            cout << "default constructor called\n";
        }

        //constructor 2
        ArrayWrapper (int n) : _p_vals( new int[ n ] ) , _size( n ) {
            cout << "constructor 2 called\n";
        }

        //move constructor
        ArrayWrapper (ArrayWrapper&& other) : _p_vals(other._p_vals), _size(other._size) {  
            cout << "move constructor called\n";
            other._p_vals = nullptr;
            other._size = 0;
        }

        // copy constructor
        ArrayWrapper (const ArrayWrapper& other) : _p_vals( new int[ other._size  ] ) , _size( other._size ) {
            cout << "copy constructor called\n";
            for ( int i = 0; i < _size; ++i )
                _p_vals[i] = other._p_vals[i];
        }

        ~ArrayWrapper () {
            delete [] _p_vals;
        }

        void set_val (std::initializer_list <int> vals) {
            int i = 0;
            for (auto val : vals) {
                _p_vals[i] = val;
                i++;
            }
        }
        void print_val () const {
            for (auto i = 0; i < _size ; i++){
                cout <<_p_vals[i] << ":" ;
            }
            cout << endl;
        }
};

ArrayWrapper getArrayWrapper () {
    ArrayWrapper A(5);
    A.set_val({1,2,3,4,5});
    return A;
}

int main () {
    ArrayWrapper arr {getArrayWrapper()};
    arr.print_val();
    return 0;
}

I am trying to ensure that the move constructor is being called. But some default copy constructor is being used since the output is simply this

constructor 2 called
1:2:3:4:5:

I am using the following g++ version

g++ (Ubuntu 6.3.0-12ubuntu2) 6.3.0 20170406

Should I make all the constructor calls explicit. I wonder how that would help though. Is there a way where I can force the program to call the move constructor and the copy constructor that I have written above?

  • 1
    Returning by reference never uses the move constructor and returning a reference to a local object is never correct. To return a local object using move semantics, return by value instead. See https://stackoverflow.com/questions/4643713/c-returning-reference-to-local-variable – François Andrieux Nov 07 '17 at 16:11
  • You can never return a reference to a local variable. Doesn't matter if it is a rvalue reference or not. When the function ends there is nothing to refer to. – NathanOliver Nov 07 '17 at 16:13
  • Possible duplicate? https://stackoverflow.com/questions/4986673/c11-rvalues-and-move-semantics-confusion-return-statement – François Andrieux Nov 07 '17 at 16:13
  • Okay. I removed the `&` from the getArrayWrapper function return value. But the move constructor isn't being called. In fact, the copy consructor isn't being called either. Some default constructor is being used for copying the contents of A into arr. Can you suggest how to forcefully use the move constructor above? – cauchyprobability Nov 07 '17 at 16:15
  • Sorry for the confusion, I will go ahead and fix my code and the question as the seg fault will sidetrack the main issue I have. – cauchyprobability Nov 07 '17 at 16:16
  • @cauchyprobability The fact that no move and no copy are being made is a good thing. You are encountering the return value optimization. Trying to force move construction here would be a net loss to performance with no gain. See https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization and https://stackoverflow.com/questions/4986673/c11-rvalues-and-move-semantics-confusion-return-statement If you insist on forcing a move, try `return std::move(A);`. – François Andrieux Nov 07 '17 at 16:30
  • I see. Thanks. Lot of new things to learn there. I found a way to disable it just to see the code in action. Using the `-fno-elide-constructors` switch to compile the code. – cauchyprobability Nov 07 '17 at 16:35

1 Answers1

0

Thanks to the commenters, I found out that the compiler is doing return value optimization (RVO) which prevents the calls to the constructors written above. I found a way to disable RVO. The -fno-elide-constructors switch in g++ works.