2016-08-05 46 views
8

Errichtet mit this online compiler, den folgenden Code:Warum kann nicht std :: tuple <int> trivial kopierbar sein?

#include <iostream> 
#include <type_traits> 
#include <tuple> 

int main() { 
    std::cout << std::is_trivially_copyable<std::tuple<int>>::value << std::endl; 
    std::cout << std::is_trivially_copyable<std::pair<int, int>>::value << std::endl; 

    std::cout << std::is_trivial<std::tuple<int>>::value << std::endl; 
    std::cout << std::is_trivial<std::pair<int, int>>::value << std::endl; 
    return 0; 
} 

Ausgänge:

0 
0 
0 
0 

ich die gleichen Ergebnisse mit Visual Studio 2015 bekommen

Warum ist das der Fall? Gibt es einen triftigen Grund eine std::tuple von POD-Typen, geschweige denn eine einfache std::pair, könnte nicht trivial kopierbar sein? Ich nehme an, dass ihre Implementierungen einige benutzerdefinierte Zuweisungsoperatoren bereitstellen, aber wie würden sie sich von den Standardversionen unterscheiden, die vom Compiler generiert werden?

+1

http://stackoverflow.com/questions/36625317/error-cannot-pass-objects-of-non-trivial-copyable-type-throught bedeutet, dass der Standard es nicht erfordert, so dass Implementierungen nicht stören – happydave

Antwort

7

Die Sache, die pair bis hin zu trivial Copyability auslöst, ist, dass der Standard erfordert, dass die Copy/Move-Zuweisungsoperatoren trivial sind. Der Standard deklariert explizit, dass die Konstruktoren copy/move standardmäßig sind, aber nicht für die Zuweisungen. Eine Implementierung könnte sie ebenfalls als Standard verwenden, aber der Standard erfordert dies nicht.

Es gibt keinen wirklich guten Grund, warum der Standard es nicht erfordert. Aber das tut es nicht.

Für tuple, Dinge sind ein Los komplizierter. Viele tuple Implementierungen basieren darauf, dass sie einen Speicherpuffer der richtigen Größe/Ausrichtung haben, und verwenden die Platzierung new, um die einzelnen Mitglieder innerhalb dieses Puffers zu konstruieren. Das ist alles in Ordnung und gut, aber ein solcher Typ muss einen manuellen Kopier-/Verschiebungskonstruktor implementieren, da er den Kopier-/Verschiebungskonstruktor jedes Typs aufrufen muss. Selbst wenn es wüsste, dass sie alle nur kopierbar waren und sie über memcpy kopierten, ist das immer noch eine manuelle Operation. Und das disqualifiziert es von trivialer Kopierbarkeit.

Nun gibt es Implementierungen von tuple, die trivial kopierbar sein könnten, wenn die Typen trivial kopierbar sind. Aber es gibt keine Notwendigkeit, sie auf diese Weise umzusetzen. Und es würde tuple Implementierungen enorm erschweren, sie dazu zu zwingen, sich selbst in eine Richtung zu implementieren, wenn alle Typen trivial kopierbar sind, und sie anders umzusetzen.

6

Da std::tuple copy/move ctor und Zuweisungsoperatoren hat, macht es die Klasse nicht-trivial kopierbar.

Siehe cpp reference:

Ein trivialer kopierbar Klasse eine Klasse ist, dass

Has no non-trivial copy constructors (this also requires no virtual functions or virtual bases) 
Has no non-trivial move constructors 
Has no non-trivial copy assignment operators 
Has no non-trivial move assignment operators 
Has a trivial destructor 

Aber std::tuple alle oben genannten und Zuweisungsoperatoren hat.

+0

Die Antwort ist nicht vollständig, ohne zu beweisen, dass die speziellen Elementfunktionen des Tupels nicht trivial sind. –

+1

Durch die Definition von [std :: tuple] (http://en.cppreference.com/w/cpp/utility/tuple) Kopieren/Verschieben von Ctors/Zuweisungen bedeutet dies bereits, dass solche ctors/operators nicht trivial sind. – Mine