jeudi 17 avril 2014

pointeurs - initialiseur C++ répertorie avec les syndicats, pourquoi différents résultats ? -Débordement de pile


I have the following program:


#include <initializer_list>
#include <iostream>

class A;
class nih {
public:
virtual void apply(A & a) const { std::cout << "generic" << std::endl; };
};

union niit;
class A {
public:
int s; char kau;
A() : s(1), kau('-') { }
A(std::initializer_list<niit> k);
};

class sn : public nih { int s; public: sn(int x) : s(x) { }
virtual void apply(A & a) const { a.s=s; } };
class kaun : public nih { char kau; public: kaun(char x) : kau(x) { }
virtual void apply(A & a) const { a.kau=kau; } };
union niit { sn sni; kaun kauni; nih nihi;
niit(const sn & s) : sni(s) { }
niit(const kaun & k) : kauni(k) { }
};

A::A(std::initializer_list<niit> k) {
const niit *n=k.begin();
for(int i=0;i<k.size();i++) {
const nih* p=&n[i].nihi;
p->apply(*this);
}
}

int main(int argc, char**argv) {
A r {kaun('a'),sn(91)};
std::cout << r.s << r.kau << std::endl;
}

I get the expected result, which is 91a. However, if I change the line


p->apply(*this);

to the following:


((const nih*)(&n[i].nihi))->apply(*this);

which should be replacement with an equivalent value, it no longer works, and instead it prints:


generic
generic
0

That is, it executes the generic method from nih. Why is that? I tried gcc 4.6 with option -std=c++0x, in case it matters.




A union can only be used with POD types, and as such cannot have members with virtual functions or nontrivial constructors/destructors, so this is undefined behaviour. Read (taken from this answer) §9.5.1 of the standard:



A union can have member functions (including constructors and destructors), but not virtual functions. A union shall not have base classes. A union shall not be used as a base class. An object of a class with a non-trivial constructor, a non-trivial copy-constructor, a non-trivial destructor, or a non-trivial copy assignment operator cannot be a member of a union, nor can an array of such objects. If a union contains a static data member, or a member of a reference type, the program is ill-formed.



And



In certain contexts, C++ allows only POD types to be used. For example, a union in C++ cannot contain a class that has virtual functions, or nontrivial constructors or destructors. This restriction is imposed because the compiler cannot know which constructor or destructor should be called for a union.




I have the following program:


#include <initializer_list>
#include <iostream>

class A;
class nih {
public:
virtual void apply(A & a) const { std::cout << "generic" << std::endl; };
};

union niit;
class A {
public:
int s; char kau;
A() : s(1), kau('-') { }
A(std::initializer_list<niit> k);
};

class sn : public nih { int s; public: sn(int x) : s(x) { }
virtual void apply(A & a) const { a.s=s; } };
class kaun : public nih { char kau; public: kaun(char x) : kau(x) { }
virtual void apply(A & a) const { a.kau=kau; } };
union niit { sn sni; kaun kauni; nih nihi;
niit(const sn & s) : sni(s) { }
niit(const kaun & k) : kauni(k) { }
};

A::A(std::initializer_list<niit> k) {
const niit *n=k.begin();
for(int i=0;i<k.size();i++) {
const nih* p=&n[i].nihi;
p->apply(*this);
}
}

int main(int argc, char**argv) {
A r {kaun('a'),sn(91)};
std::cout << r.s << r.kau << std::endl;
}

I get the expected result, which is 91a. However, if I change the line


p->apply(*this);

to the following:


((const nih*)(&n[i].nihi))->apply(*this);

which should be replacement with an equivalent value, it no longer works, and instead it prints:


generic
generic
0

That is, it executes the generic method from nih. Why is that? I tried gcc 4.6 with option -std=c++0x, in case it matters.



A union can only be used with POD types, and as such cannot have members with virtual functions or nontrivial constructors/destructors, so this is undefined behaviour. Read (taken from this answer) §9.5.1 of the standard:



A union can have member functions (including constructors and destructors), but not virtual functions. A union shall not have base classes. A union shall not be used as a base class. An object of a class with a non-trivial constructor, a non-trivial copy-constructor, a non-trivial destructor, or a non-trivial copy assignment operator cannot be a member of a union, nor can an array of such objects. If a union contains a static data member, or a member of a reference type, the program is ill-formed.



And



In certain contexts, C++ allows only POD types to be used. For example, a union in C++ cannot contain a class that has virtual functions, or nontrivial constructors or destructors. This restriction is imposed because the compiler cannot know which constructor or destructor should be called for a union.



0 commentaires:

Enregistrer un commentaire