[C++03] Ist das definiertes Verhalten?


  • Administrator

    Folgendes habe ich in einer Bibliothek gefunden und mich gefragt, ob das nicht undefiniertes Verhalten ist:

    class base
    {
    private:
      int* m_data;
    
    protected:
      int get_data() const { return *m_data; }
    
    public:
      base(base const& other)
      {
        // nicht trivial
      }
    
      base& operator =(base other)
      {
        // nicht trivial
      }
    };
    
    class derived
      : public base
    {
    public:
      derived(/* mehrere parameter */)
      {
        // umfassende Initialisierung
        // kein trivialer Konstruktor
      }
    
      // copy constructor und assignment operator ebenfalls nicht trivial
    
      int get_xyz() { return get_data(); }
    };
    
    void create_data(int** data)
    {
      *data = new int(10);
    }
    
    void release_data(int** data)
    {
      delete *data;
    }
    
    // ...
    
    derived d;
    create_data((int**)&d);  // 1
    
    std::cout << d.get_xyz() << '\n';
    
    release_data((int**)&d); // 2
    

    Es kommt keinerlei virtual vor.

    Das ist doch undefiniertes Verhalten? Oder täusche ich mich da? derived ist doch kein POD? Dass der Cast bei 1 und 2 das gewünschte macht, ist zwar wahrscheinlich aber nicht definiert?

    Grüssli



  • Natürlich ist das UB.



  • Natürlich ist das DB.


  • Mod

    Sollte definiertes Verhalten sein:

    C++-Standard schrieb:

    A standard-layout class is a class that:
    — has no non-static data members of type non-standard-layout class (or array of such types) or reference,
    — has no virtual functions (10.3) and no virtual base classes (10.1),
    — has the same access control (Clause 11) for all non-static data members,
    — has no non-standard-layout base classes,
    — either has no non-static data members in the most derived class and at most one base class with
    non-static data members, or has no base classes with non-static data members, and
    — has no base classes of the same type as the first non-static data member.108
    A standard-layout struct is a standard-layout class defined with the class-key struct or the class-key class.
    A standard-layout union is a standard-layout class defined with the class-key union.

    ...

    A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its
    initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [ Note:
    There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning,
    as necessary to achieve appropriate alignment. — end note ]



  • I stand corrected...trotzdem etwas, was ich nie im Leben tun würde...


  • Administrator

    @SeppJ,
    Ist das der C++11 oder C++03 Standard? In C++11 wurde sowas doch gelockert? Dein Zitat klingt mir ehrlich gesagt nach dem C++11 Standard. Ich mag mich gerade nicht daran erinnern, jemals etwas von standard-layout im C++03 Standard gelesen zu haben. Daher frage ich kurz nach 🙂

    Grüssli



  • Ja das ist C++ 11. In C++ 03 war das definitiv noch UB...


  • Mod

    Ja, das ist C++11, ich dachte, deine Frage wäre aktuell. Den alten kann ich ja auch noch mal rausholen. Moment...

    ...edit: Ja, ist undefiniert, weil dort die Klausel mit dem Cast für POD-structs gilt und die dürfen keinen nutzerdefinierten Konstruktor haben.

    Ich würde da aber ganz pragmatisch mich trotzdem drauf verlassen. Gibt schließlich einen technischen Grund, wieso der Standard gelockert werden konnte. Keine normale Implementierung wird das falsch machen.


  • Administrator

    dot schrieb:

    ...trotzdem etwas, was ich nie im Leben tun würde...

    Da sind die Leute der Khronos Group wohl anderer Meinung. Ich habe das nämlich von ihrem OpenCL C++ Header:
    http://www.khronos.org/registry/cl/api/1.1/cl.hpp

    Der hat sowieso ein paar seltsame Eigenheiten. Ganz nett finde ich z.B. sowas:

    cl::Program program(/* ... */);
    cl::Kernel kernel(/* ... */);
    
    program(); // 1
    kernel();  // 2
    

    Falls hier jemand wirklich meint, dass bei 1 das Programm oder bei 2 der Kernel ausgeführt wird, weit gefehlt! Damit erhält man nur das C Handle auf das Programm, bzw. den Kernel, zurück. Ist doch logisch!

    Grüssli


  • Administrator

    @SeppJ,
    Danke für das Nachschauen.

    Ja, ich nehme auch an, dass es sehr wahrscheinlich ist, dass es meistens funktionieren wird. Finde es aber trotzdem sehr fragwürdig, sowas einzusetzen. Erst recht in einem Header eines Standards.

    Grüssli



  • Dravere schrieb:

    Da sind die Leute der Khronos Group wohl anderer Meinung. Ich habe das nämlich von ihrem OpenCL C++ Header:
    http://www.khronos.org/registry/cl/api/1.1/cl.hpp

    Ja, diese OpenCL C++ API ist grottig...


  • Mod

    SeppJ schrieb:

    Sollte definiertes Verhalten sein:

    C++-Standard schrieb:

    A standard-layout class is a class that:
    — has no non-static data members of type non-standard-layout class (or array of such types) or reference,
    — has no virtual functions (10.3) and no virtual base classes (10.1),
    — has the same access control (Clause 11) for all non-static data members,
    — has no non-standard-layout base classes,
    — either has no non-static data members in the most derived class and at most one base class with
    non-static data members, or has no base classes with non-static data members, and
    — has no base classes of the same type as the first non-static data member.108
    A standard-layout struct is a standard-layout class defined with the class-key struct or the class-key class.
    A standard-layout union is a standard-layout class defined with the class-key union.

    ...

    A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its
    initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [ Note:
    There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning,
    as necessary to achieve appropriate alignment. — end note ]

    Allerdings ist ein Objekt, das ein Basisklassensubobjekt eines Standardlayout-Typen enthält, kein Standardlayout-Objekt (auch nicht in Teilen). Also doch UB. siehe auch 1.8/1 ("standard-layout struct object" oben impliziert, dass der dynamische Typ ein Standardlayout-Typ ist) und 10./4.


Anmelden zum Antworten