Je lisais Want Speed? Pass by Value sur le C++ Next blog et créé this program pour avoir une idée de copie élision et déplacer la sémantique en C++ 0x:Copier élision sur Visual C++ 2010 Beta 2
#include <vector>
#include <iostream>
class MoveableClass {
public:
MoveableClass() : m_simpleData(0), instance(++Instances) {
std::cout << "Construct instance " << instance << " (no data)" << std::endl;
}
MoveableClass(std::vector<double> data) : m_data(std::move(data)), m_simpleData(0), instance(++Instances) {
std::cout << "Construct instance " << instance << " (with data)" << std::endl;
}
MoveableClass(int simpleData) : m_simpleData(simpleData), instance(++Instances) {
std::cout << "Construct instance " << instance << " (with simple data)" << std::endl;
}
MoveableClass(const MoveableClass& other)
: m_data(other.m_data), m_simpleData(other.m_simpleData), instance(++Instances)
{
std::cout << "Construct instance " << instance << " from a copy of " << other.instance << std::endl;
Elided = false;
}
MoveableClass(MoveableClass&& other)
: m_data(std::move(other.m_data)), m_simpleData(other.m_simpleData), instance(++Instances)
{
std::cout << "Construct instance " << instance << " from a move of " << other.instance << std::endl;
Elided = false;
}
MoveableClass& operator=(MoveableClass other) {
std::cout << "Assign to instance " << instance << " from " << other.instance << std::endl;
other.Swap(*this);
return *this;
}
~MoveableClass() {
std::cout << "Destroy instance " << instance << std::endl;
--Instances;
}
void Swap(MoveableClass& other) {
std::swap(m_data, other.m_data);
std::swap(m_simpleData, other.m_simpleData);
}
static int Instances;
static bool Elided;
private:
int instance;
int m_simpleData;
std::vector<double> m_data;
};
int MoveableClass::Instances = 0;
bool MoveableClass::Elided = true;
std::vector<double> BunchOfData() {
return std::vector<double>(9999999);
}
int SimpleData() {
return 9999999;
}
MoveableClass CreateRVO() {
return MoveableClass(BunchOfData());
}
MoveableClass CreateNRVO() {
MoveableClass named(BunchOfData());
return named;
}
MoveableClass CreateRVO_Simple() {
return MoveableClass(SimpleData());
}
MoveableClass CreateNRVO_Simple() {
MoveableClass named(SimpleData());
return named;
}
int main(int argc, char* argv[]) {
std::cout << "\nMove assign from RVO: " << '\n';
{
MoveableClass a;
a = CreateRVO();
}
std::cout << "Move elided: " << (MoveableClass::Elided ? "Yes" : "No") << '\n';
MoveableClass::Elided = true; // reset for next test
std::cout << "\nMove assign from RVO simple: " << '\n';
{
MoveableClass a;
a = CreateRVO_Simple();
}
std::cout << "Move elided: " << (MoveableClass::Elided ? "Yes" : "No") << '\n';
MoveableClass::Elided = true; // reset for next test
std::cout << "\nMove assign from NRVO: " << '\n';
{
MoveableClass a;
a = CreateNRVO();
}
std::cout << "Move elided: " << (MoveableClass::Elided ? "Yes" : "No") << '\n';
MoveableClass::Elided = true; // reset for next test
std::cout << "\nMove assign from NRVO simple: " << std::endl;
{
MoveableClass a;
a = CreateNRVO_Simple();
}
std::cout << "Move elided: " << (MoveableClass::Elided ? "Yes" : "No") << '\n';
MoveableClass::Elided = true; // reset for next test
}
Voici la sortie que je reçois lors de la compilation en mode de déclenchement sur Visual C++ 10,0 (bêta 2):
mouvement de classer RVO:
Construct exemple 1 (pas de données)
Construct exemple 2 (avec données)
Construct exemple 3 d'un mouvement de 2
Destroy exemple 2
Attribuer à l'instance 1 de 3
Destroy exemple 3
Destroy exemple 1
Déplacer élision: NonDéplacer assigner de la simple RVO:
Construct exemple 1 (pas de données)
Construct exemple 2 (avec des données simples)
Assigner à une instance de 2
Destro y exemple 2
Détruire exemple 1
mouvement élidée: Ouimouvement classer de NRVO:
Construct exemple 1 (pas de données)
Construct exemple 2 (avec données)
Assign pour exemple 1 à partir de 2
Détruisez exemple 2
Détruisez exemple 1
Déplacer élision: OuiDéplacer assigner de la simple NRVO:
Construct exemple 1 (pas de données)
Construct exemple 2 (avec des données simples)
Attribuer à l'instance 1 de 2
Destroy exemple 2
Destroy exemple 1
Déplacer élision: Oui
Cependant , Je suis perplexe par une chose. Comme vous pouvez le voir, tous les mouvements sont élidés sauf le premier. Pourquoi le compilateur ne peut-il pas exécuter RVO avec une MoveableClass (std :: vector) à la ligne 86, mais avec une MoveableClass (int) à la ligne 97? Est-ce juste un bug avec MSVC ou y at-il une bonne raison à cela? Et s'il y a une bonne raison, pourquoi peut-il encore effectuer NRVO sur une MoveableClass (std :: vector) à la ligne 91?
Je voudrais le comprendre afin que je puisse aller dormir heureux. :)
Une très bonne question. Pour ce que ça vaut, g ++ 4.3.3 élide tous ces mouvements, même avec le drapeau '-O0'. – Thomas
Merci Thomas. C'est intéressant que cela fonctionne sur GCC. Peut-être que cela suggère que quelque chose ne va pas avec la mise en œuvre MSVC. – dvide
Je pense que cela souligne à quel point le gouffre est vaste entre "le compilateur devrait" et "le compilateur". – Crashworks