15

Hi I created a class Foo with a noexcept move constructor using gcc 4.7 and set the vector reserve size to 2 so that it would have to reallocate the size when adding the 3rd item. It seems it is calling the copy constructor instead of the move constructor when doing this. Am I missing something here?

#include <vector> #include <iostream> class Foo { public: Foo(int x) : data_(x) { std::cout << " constructing " << std::endl; } ~Foo() { std::cout << " destructing " << std::endl; } Foo& operator=(const Foo&) = default; Foo& operator=(Foo&&) = default; Foo(Foo&& other) noexcept : data_(std::move(other.data_)) { std::cout << " Move constructing " << std::endl; } Foo(const Foo& other) noexcept : data_(other.data_) { std::cout << " Copy constructing " << std::endl; } private: int data_; }; int main ( int argc, char *argv[]) { std::vector<Foo> v; v.reserve(2); v.emplace_back(1); std::cout << "Added 1" << std::endl; v.emplace_back(2); std::cout << "Added 2" << std::endl; v.emplace_back(3); std::cout << "Added 3" << std::endl; std::cout << "v size: " << v.size() << std::endl; } 

output:

 constructing Added 1 constructing Added 2 constructing Copy constructing Copy constructing destructing destructing Added 3 v size: 3 destructing destructing destructing 
4
  • 1
    My clang build doesn't fire the copy ctor once. get a smarter gcc ? Commented Sep 6, 2013 at 10:31
  • 1
    It works as expected (that is, vector calls the move constructor) with GCC 4.8.1. Commented Sep 6, 2013 at 10:32
  • 2
    It works fine with gcc 4.8.1. Could be a bug in 4.7 Commented Sep 6, 2013 at 10:32
  • hmmm that makes sense I need to upgrade to gcc 4.8.1. I couldn't figure this out forever it was bothering me... Seems like just a bug then. Thanks so much! Commented Sep 6, 2013 at 10:36

1 Answer 1

15

After tinkering with it a bit with both GCC 4.7 and 4.8, it seems that it is indeed a bug in 4.7, which only appears when the class' destructor is not marked noexcept:

struct Foo { Foo() {} ~Foo() noexcept {} Foo(Foo&&) noexcept { std::cout << "move constructor" << std::endl; } Foo(const Foo&) noexcept { std::cout << "copy constructor" << std::endl; } }; int main() { std::vector<Foo> v; v.reserve(2); v.emplace_back(); v.emplace_back(); v.emplace_back(); } 

GCC 4.7 displays:

move constructor move constructor 

If we remove noexcept from the destructor:

struct Foo { Foo() {} ~Foo() {} Foo(Foo&&) noexcept { std::cout << "move constructor" << std::endl; } Foo(const Foo&) noexcept { std::cout << "copy constructor" << std::endl; } }; 

GCC 4.7 displays:

copy constructor copy constructor 

GCC 4.8 uses the move constructor in both cases.

Sign up to request clarification or add additional context in comments.

1 Comment

+1 Found the bug. G++ 4.7 does not apply the rule that destructors are noexcept, so you need to add an explicit noexcept specification on the destructor. GCC 4.8 correctly makes the destructor noexcept as required by C++11.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.