2013-09-06 11 views
12

Witam Stworzyłem klasę Foo z konstruktorem ruchu noexcept przy użyciu gcc 4.7 i ustawiłem wielkość rezerwy wektorowej na 2, aby przy dodawaniu trzeciego elementu trzeba było ponownie przydzielić rozmiar. Wygląda na to, że podczas wykonywania tej operacji wywołuje on konstruktor kopiowania zamiast konstruktora ruchu. Czy coś mi umyka?Ponowne przypisanie wektora używa egzemplarza zamiast konstruktora ruchu

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

wyjściowa:

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

Moja kompozycja klang nie uruchamia jednokrotnego kopiowania. zdobyć mądrzejszy gcc? – WhozCraig

+1

Działa zgodnie z oczekiwaniami (tzn. "Wektor" wywołuje konstruktor ruchu) za pomocą GCC 4.8.1. –

+2

Działa dobrze z [gcc 4.8.1] (http://ideone.com/SXoMw2). Może być bug w 4.7 – Angew

Odpowiedz

13

Po majstrować przy nim trochę z obu GCC 4.7 i 4.8, wydaje się, że to rzeczywiście jest to błąd w 4.7, który pojawia się tylko wtedy, gdy klasa destruktor jest nie oznaczone 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 wyświetlacze:

move constructor 
move constructor 

Jeśli usuwamy noexcept z destruktora:

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 Wyświetlanie:

copy constructor 
copy constructor 

GCC 4.8 używa konstruktora ruch w obu przypadkach.

+9

+1 [Znaleziono błąd] (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56191). 'G ++ 4.7 nie stosuje reguły, że destruktory nie są wyjątkiem, więc musisz dodać wyraźną specyfikację noexcept do destruktora. GCC 4.8 poprawnie powoduje, że destruktor nie jest zgodny z wymaganiami C++ 11. " –

Powiązane problemy