7

There are two vectors std :: vector and QVector. We have to check how "shift" elements when inserted. (Is constructed two vectors with the five elements and inserted zero element) I've this code:

#include <QVector>
#include <QTextStream>

struct MoveTest
{
    int i;

    MoveTest()                       {}
    MoveTest(const MoveTest& other)  {QTextStream(stdout) << "constr copy" << endl;}
    MoveTest(MoveTest &&other)       {QTextStream(stdout) << "constr move" << endl;}
    ~MoveTest()                      {}

    inline MoveTest&    operator=   (const MoveTest& other) {QTextStream(stdout) << "copy" << endl;}
    inline MoveTest&    operator=   (MoveTest &&other)      {QTextStream(stdout) << "move" << endl;}
};

int main(int argc, char *argv[])
{
    QTextStream(stdout) << "std::move:" << endl;
    MoveTest t1;
    MoveTest t2(std::move(t1));
    t1 = std::move(t2);

    QTextStream(stdout) << "QVector:" << endl;
    QVector<MoveTest> qmTest(5);
    qmTest.insert(qmTest.begin(), MoveTest());

    QTextStream(stdout) << "std::vector:" << endl;
    std::vector<MoveTest> mTest(5);
    mTest.insert(mTest.begin(), MoveTest());

    return 0;
}

My output with gcc 4.7.2, QMAKE_CXXFLAGS += -std=c++0x:

std::move:
constr move
move
QVector:
constr copy
constr copy
constr copy
constr copy
constr copy
constr copy
copy
copy
copy
copy
copy
copy
std::vector:
constr move
constr copy
constr copy
constr copy
constr copy
constr copy

How to insert elements with an internal shift without copying? What GCC flags are needed?

Inder Kumar Rathore
  • 39,458
  • 17
  • 135
  • 184
user1931823
  • 105
  • 1
  • 2
  • 6
  • a gift for you http://thbecker.net/articles/rvalue_references/section_01.html ( yeah I'm getting emotional these days ... ) – user1824407 Dec 27 '12 at 10:45
  • possible duplicate of [How to enforce move semantics when a vector grows?](http://stackoverflow.com/questions/8001823/how-to-enforce-move-semantics-when-a-vector-grows) – David Schwartz Dec 27 '12 at 10:47

3 Answers3

5

Since your move operator can throw an exception, std::vector can't use it. What would it do if the operator threw an exception halfway through the resize process? Declare it noexcept if it cannot throw an exception and the the vector implementation can use it.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • I'm added noexcept specifier, but out wasnt changed. – user1931823 Dec 27 '12 at 12:07
  • Because your class has a data member. As the rule says, "A declaration of a destructor that does not have an exception-specification is implicitly considered to have the same exception-specification as an implicit declaration." – David Schwartz Dec 27 '12 at 17:51
1

May be useful to someone.

struct MoveTest
{
    int i;

    MoveTest()                      {}
    MoveTest(MoveTest&&) noexcept   {std::cout << "constr move\n";}
    MoveTest(const MoveTest&)       {std::cout << "constr copy\n";}
    ~MoveTest() noexcept            {}

    MoveTest&   operator=   (MoveTest&&) noexcept   {std::cout << "move\n"; return *this;}
    MoveTest&   operator=   (const MoveTest&)       {std::cout << "copy\n"; return *this;}
};
Q_DECLARE_TYPEINFO(MoveTest, Q_MOVABLE_TYPE);

int main(int argc, char *argv[])
{
    std::cout << "std::move:\n";
    MoveTest t1;
    MoveTest t2(std::move(t1));
    MoveTest t3(std::move_if_noexcept(t2));
    t2 = std::move(t3);
    t1 = std::move_if_noexcept(t2);
    std::cout << "\n";

    std::cout << "QVector:\n";
    QVector<MoveTest> qmTest(5);
    qmTest.insert(qmTest.begin(), MoveTest());
    std::cout << "\n";

    std::cout << "std::vector:\n";
    std::vector<MoveTest> mTest(5);
    mTest.insert(mTest.begin(), MoveTest());

    return 0;
}

Out:

std::move:
constr move
constr move
move
move

QVector:
constr copy
constr copy

std::vector:
constr move
constr move
constr move
constr move
constr move
constr move
user1931823
  • 105
  • 1
  • 2
  • 6
1

Surely containers in QT are capable of coping with move semantics. Run the example below and see for yourself.

#include <QCoreApplication>
#include <QVector>
#include <iostream>

struct MoveTest
{
    int i;

    MoveTest()                      {}
    MoveTest(MoveTest&&) noexcept   {std::cout << "constr move\n";}
    MoveTest(const MoveTest&)       {std::cout << "constr copy\n";}
    ~MoveTest() noexcept            {}

    MoveTest&   operator=   (MoveTest&&) noexcept   {std::cout << "move\n"; return *this;}
    MoveTest&   operator=   (const MoveTest&)       {std::cout << "copy\n"; return *this;}
};
Q_DECLARE_TYPEINFO(MoveTest, Q_MOVABLE_TYPE);

int main(int argc, char *argv[])
{
    std::cout << "std::move:\n";
    MoveTest t1;
    MoveTest t2(std::move(t1));
    MoveTest t3(std::move_if_noexcept(t2));
    t2 = std::move(t3);
    t1 = std::move_if_noexcept(t2);
    std::cout << "\n";

    std::cout << "QVector:\n";
    QVector<MoveTest> qmTest;
    int i=5;
    while(i) {
        qmTest.append(MoveTest());
        --i;
    }
    std::cout << "\n";

    std::cout << "std::vector:\n";
    std::vector<MoveTest> mTest(5);
    mTest.insert(mTest.begin(), MoveTest());

    return 0;
}

Since two objects have similar use that doesn't mean that all member functions are the same. Check output below. Out:

std::move:
constr move
constr move
move
move

QVector:
constr move
constr move
constr move
constr move
constr move

std::vector:
constr move
constr move
constr move
constr move
constr move
constr move
Press <RETURN> to close this window...