2013-09-06 6 views
12

Hallo Ich habe eine Klasse Foo mit einem noexcept Move Konstruktor mit gcc 4.7 und legen Sie die Größe der Vektorreserve auf 2, so dass es die Größe beim Hinzufügen der 3. Element neu zuordnen müsste. Es scheint, dass es den Kopierkonstruktor anstelle des Move-Konstruktors aufruft, wenn er dies tut. Fehle ich hier etwas?Vector Reallocation verwendet Kopie anstelle von Move Konstruktor

#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; 
} 

Ausgang:

constructing 
Added 1 
constructing 
Added 2 
constructing 
Copy constructing 
Copy constructing 
destructing 
destructing 
Added 3 
v size: 3 
destructing 
destructing 
destructing 
+1

Mein clang Build feuert den copy ctor nicht einmal. einen schlaueren gcc bekommen? – WhozCraig

+1

Es funktioniert wie erwartet (das heißt, "vector" ruft den Move-Konstruktor auf) mit GCC 4.8.1. –

+2

Es funktioniert gut mit [gcc 4.8.1] (http://ideone.com/SXoMw2). Könnte ein Bug sein in 4.7 – Angew

Antwort

13

Nachdem sie mit ihm ein wenig mit sowohl GCC 4.7 und 4.8 bastelt, scheint es, dass es in der Tat in 4.7 ein Fehler ist, der erscheint nur, wenn die Klasse destructor ist nicht markiert 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 angezeigt:

move constructor 
move constructor 

Wenn wir noexcept vom destructor entfernen:

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 angezeigt:

copy constructor 
copy constructor 

GCC 4.8 verwendet den Umzug Konstruktor in beiden Fällen.

+9

+1 [Den Fehler gefunden] (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56191). 'G ++ 4.7 wendet nicht die Regel an, dass Destruktoren nicht except sind, daher müssen Sie eine explizite noexcept-Spezifikation für den Destruktor hinzufügen. GCC 4.8 macht den Destruktor korrekt, wie in C++ 11 erforderlich –