8

I have been playing around with std::vector to understand when objects are constructed, destructed, copy constructed and move constructed. To so do, I have written the following program

#include <iostream>
#include <vector>

class Test {
public:
    Test() {
        std::cout << "Constructor called for " << this << std::endl;
    }
    Test(const Test& x) {
        std::cout << "Copy Constructor called for " << this << std::endl;
    }
    Test(Test&& x) {
        std::cout << "Move Constructor called for " << this << std::endl;
    }
    ~Test() {
        std::cout << "Destructor called for " << this << std::endl;
    }
};

int main() {
    std::vector<Test> a( 1 );
    a.resize(3);

    return 0;
}

When a is resized, reallocation happens. My guess would have been that the object a[0] is moved constructed to the new a[0]. But, with libc++ and libstdc++, it seems that the copy constructor is called and not the move constructor. Is there any reason for such a behaviour?

Stephan Dollberg
  • 32,985
  • 16
  • 81
  • 107
InsideLoop
  • 6,063
  • 2
  • 28
  • 55

2 Answers2

15

I just found the answer to the question. The move constructor has to be declared noexcept to do so. When such a change has been done

Test(Test&& x) noexcept {
    std::cout << "Move Constructor called for " << this << std::endl;
}

the move constructor is called.

InsideLoop
  • 6,063
  • 2
  • 28
  • 55
  • you'd think the optimiser should deduce that your constructor doesn't throw and use it even without the noexcept specifier. – gbjbaanb Jan 27 '15 at 08:33
  • @gbjbaanb Does the compiler _ever_ infer modifiers? It doesn't for `const` (as a postfix). – ApproachingDarknessFish Jan 27 '15 at 08:38
  • 3
    @gbjbaanb I think you technically could make `cout` throw via [`ios::exceptions`](http://en.cppreference.com/w/cpp/io/basic_ios/exceptions). – Baum mit Augen Jan 27 '15 at 08:38
  • 5
    @gbjbaanb: The optimizer should not alter the meaning of the code. Deducing `noexcept` would be nice feature, but the standard does not include it. – Raoul Steffen Jan 27 '15 at 08:42
  • 1
    I did read it somewhere when I was looking up the spec.. ah [in Pubby's answer](http://stackoverflow.com/questions/10787766/when-should-i-really-use-noexcept?rq=1). What is interesting is that the compiler-generated move constructor does not have noexcept apparently. Its times like this that I think C++ has gone too far into 'overcomplex' territory as its detractors claim. :-( – gbjbaanb Jan 27 '15 at 11:13
  • @gbjbaanb, why do you think the implicit move constructor for `Test` would not be `noexcept`? [Did you try it?](http://ideone.com/a27jPa) It has no members and no bases, so the implicit move ctor would be empty, and deduced as `noexcept` – Jonathan Wakely Jan 27 '15 at 14:34
  • @JonathanWakely I guess it depends on the compiler - I read it on t'internet that the default one didn't include it. And here in comments, I'm told that the standard does not include deducing such things :-) I'm also at work and stuck on VS2010, so no, I haven't tried it. :-( What I am sure of is that it is something that is inducing a lot of confusion, which isn't a good thing for the language to thrive. – gbjbaanb Jan 27 '15 at 16:38
4

Just as @InsideLoop's answer said, the move constructor has to be declared "noexcept" to be called.

It is because in the vector::resize() function call stack, we can find move_if_noexcept() is called in function __construct_backward().(see [your library path]/include/c++/v1/memory line:1531)

construct(__a, _VSTD::__to_raw_pointer(__end2-1), _VSTD::move_if_noexcept(*--__end1));

According to the C++11 standard, we know that move constructor is used for temporary right value in normal. So the move constructor throwing exception is such a dangerous thing, and we can declare "noexcept" for the move constructor to avoid it.

Using move_if_noexcept(), although it loss in performance, but can make the process safe. And the function will activate the move constructor when move constructor is declared "noexcept".

(Sorry for my poor English.)

YuChan
  • 197
  • 1
  • 1
  • 8