0

I'm trying to understand the new move constructor from C++11 following an example from the book "Professional C++", 2nd ed., chapter 9, page 279.

Here is my class header file Spreadsheet.h:

class Spreadsheet 
{
    public:
        Spreadsheet(int inWidth = kMaxWidth, int inHeight = kMaxHeight);
        Spreadsheet(const Spreadsheet& src);
        Spreadsheet(Spreadsheet&& src);
        ~Spreadsheet();

        int getId() const;
        int getWidth() const;
        int getHeight() const;
        void setCellAt(int x, int y, const SpreadsheetCell& cell);
        SpreadsheetCell getCellAt(int x, int y) const;

        Spreadsheet& operator=(const Spreadsheet& rhs);
        Spreadsheet& operator=(Spreadsheet&& rhs);
    private:
        bool inRange(int val, int upper) const;
        void copyFrom(const Spreadsheet& src);
        void moveFrom(Spreadsheet& src);
        void freeMemory();

        int mWidth, mHeight, mId;
        SpreadsheetCell** mCells;

        static int sCounter;

        const static int kMaxWidth = 100;
        const static int kMaxHeight = 100;
};

And here are some snippets from Spreadsheet.cpp:

Spreadsheet::Spreadsheet(Spreadsheet&& src)
{
    std::cout << "Move ctor" << std::endl;
    moveFrom(src);
}

void Spreadsheet::moveFrom(Spreadsheet& src)
{
    mId = src.mId;
    mWidth = src.mWidth;
    mHeight = src.mHeight;
    mCells = src.mCells;

    src.mWidth = 0;
    src.mHeight = 0;
    src.mCells = nullptr;
}

Spreadsheet& Spreadsheet::operator=(Spreadsheet&& rhs)
{
    std::cout << "Move assignment" << std::endl;
    if (this == &rhs) {
        return *this;
    }

    freeMemory();
    moveFrom(rhs);

    return *this;
}

void Spreadsheet::freeMemory() {
    for (int i = 0; i < mWidth; i++) {
        delete [] mCells[i];
    }

    delete [] mCells;
    mCells = nullptr;
}

Then, I got this on my main:

std::vector<Spreadsheet> vec;
for (int i = 0; i < 3; i++) {
    std::cout << "Iteration " << i << std::endl;
    vec.push_back(Spreadsheet(1, 1));
    std::cout << vec[i].getId() << std::endl;
    std::cout << std::endl;
}

The programs output is like:

Iteration 0
Normal ctor
Move ctor
0

Iteration 1
Normal ctor
Move ctor
Copy ctor
1

Iteration 2
Normal ctor
Move ctor
Copy ctor
Copy ctor
3

I'd expect just calls to the move ctor instead of the copy ctor for all elements, not just the first one, as the vector resizes itself to fit the new element.

I'm compiling with clang 3.3-1 and libc++ 3.3-3:

$ clang++ -Wall -g -std=c++11 -stdlib=libc++ -lc++abi \ 
SpreadsheetTest.cpp Spreadsheet.o SpreadsheetCell.o -o SpreadsheetTest

What I can't figure out is if there is something wrong with my implementation or it's related to std::vector implementation which does not make use of move constructors.

Henrique Barcelos
  • 7,670
  • 1
  • 41
  • 66
  • 1
    See if you get something different by pre-allocating enough slots in `vec`, and declaring your move-constructor and the `moveFrom` (I'm not liking its signature) `noexcept`. – Mat Nov 03 '13 at 05:24
  • Just adding noexcept did it. Could you explain why? Also, what is the problem with the signature of `moveFrom`? – Henrique Barcelos Nov 03 '13 at 05:28
  • Think about this: what does a vector need to do when it's full and you push_back to it? And then check out the exception requirements on push_back (http://en.cppreference.com/w/cpp/container/vector/push_back). (I won't make an answer - I know the basics and have seen this before, but I'm a bit short on the details.) – Mat Nov 03 '13 at 05:30
  • When the vector is full, it needs to allocate enough memory and then move its content to the new position. It seems like if the move constructor is not `noexcept`, vector will try to use copy constructor and if it is not avaliable (which is not my case), it will try the throwing move constructor. Am I right? – Henrique Barcelos Nov 03 '13 at 05:35
  • 2
    There's a good explanation of what's going on here: [Why does reallocating a vector copy instead of moving the elements?](http://stackoverflow.com/questions/10127603/why-does-reallocating-a-vector-copy-instead-of-moving-the-elements) – godel9 Nov 03 '13 at 05:43
  • Well, sorry by the duplicate... Thanks @godel9 – Henrique Barcelos Nov 03 '13 at 05:49

0 Answers0