Kode berikut pada g++ yang dikompilasi dengan -fno-elide-constructors tampaknya memberikan hasil yang salah. Tanpa flag -fno-elide-constructors, tampaknya berfungsi dengan baik.

  1. Apakah ini bug dalam program saya di suatu tempat? (Seperti yang ditunjukkan oleh pengalaman, kemungkinan besar bug itu akan menyerang saya segera setelah saya selesai memposting ini - jika ada!)

  2. Jika tidak, apa yang memberikan hasil yang tampaknya salah dengan flag -fno-elide-constructors?


#include <iostream>
/*
Compile with g++ -fno-elide-constructors and without the  
-fno-elide-constructors flag
 */

class ClassA {
public:
    ClassA() : myVal(100) {
        std::cout << "default constructor called" << std::endl;
    }
    ClassA(int iX) : myVal(iX) {
        std::cout << "constructor with int arg called" << std::endl;
        std::cout << "myVal: " << myVal << std::endl;
    }
    ~ClassA() {
    std::cout << "destructor called" << std::endl;
    }
    ClassA(const ClassA&) {
        std::cout << "copy constructor called" << std::endl;
    }
    /*
    ClassA(ClassA&&) {
        std::cout << "MOVE constructor called" << std::endl;
    }
    ClassA& operator=(ClassA&& otherA){
        std::cout << "Move-Assignment Operator called" << std::endl;       
        return *this;
        }  */
    int get_myVal() {std::cout << "myVal: " <<  myVal << std::endl; return myVal;  }
private:
    int myVal;
};

ClassA  myFunc(int iN){
    auto myTmp = ClassA(iN);
    return myTmp;
}
int main()
{
    //auto a0 =  ClassA{200};  //myFunc(200);
    //ClassA b0 = a0;
    auto a0 = myFunc(300);
    std::cout << a0.get_myVal()  << std::endl;
    return 0;
}

Terima kasih atas waktu & tanggapan Anda. (Saya minta maaf atas pemformatan kode yang buruk - saya mencoba dan menyerah!)

-2
user5920427 12 November 2017, 22:03

1 menjawab

Jawaban Terbaik

Anda tidak menginisialisasi ClassA::myVal di konstruktor salinan ClassA. Jadi nilai a0.myVal tidak tentu karena a0 diinisialisasi melalui inisialisasi salin.

Ini terungkap hanya ketika kompilasi dengan "-fno-elide-constructors" karena standar memungkinkan kompiler untuk menghilangkan salinan bahkan ketika itu mengubah perilaku program yang dapat diamati. Dalam hal ini, ketika kompilasi tanpa "-fno-elide-constructors", gcc mengkonstruksi a0 secara langsung, tanpa konstruktor perantara, dan a0.myVal akhirnya menjadi 300. Saat Anda secara eksplisit menonaktifkan penghapusan salinan, gcc menyimpan semua salinan perantara, sehingga nilai awal dari ClassA sementara yang dibuat melalui inisialisasi langsung akan hilang oleh konstruktor salinan yang tidak menyalin nilai tersebut.

Jika Anda menginisialisasi ClassA::myVal ke nilai dari objek yang disalin di konstruktor salinan ClassA, Anda mendapatkan perilaku yang Anda harapkan:

ClassA(const ClassA& other) : myVal(other.myVal) {
    std::cout << "copy constructor called" << std::endl;
}

Demo langsung

2
Miles Budnek 12 November 2017, 20:01