"variant-type 개체"를 구현하는 데 수년 동안 성공적으로 사용해온 코드가 있습니다. 즉, 다양한 유형의 값을 보유 할 수 있지만 가장 큰 유형의 메모리 만 사용합니다 (대략). 이 코드는 비 POD 데이터 유형을 지원한다는 점을 제외하고는 태그가 붙은 유니온과 유사합니다. char 버퍼, placement new/delete 및 reinterpret_cast <>을 사용하여이 마법을 달성합니다. 게재 위치 - 새로운 vcc gcc 4.4.3 엄격한 앨리어싱 규칙
내가 최근에 (-03 및 -Wall 포함) GCC 4.4.3에서이 코드를 컴파일 시도하고,이 같은 경고를 많이 가지고 : 내가 읽은 바로는warning: dereferencing type-punned pointer will break strict-aliasing rules
을,이 표시는 gcc의 새로운 옵티 마이저가 '버그가있는'코드를 생성 할 수 있다고 생각합니다. 분명히 피하고 싶습니다.
아래 코드의 '장난감 버전'을 붙여 넣었습니다. 비 -POD 데이터 유형을 계속 지원하면서 gcc 4.4.3에서 코드를 안전하게 만들 수있는 방법이 있습니까? 필자는 최후의 수단으로 항상 -fno-strict-aliasing을 사용하여 코드를 컴파일 할 수 있다는 것을 알고 있지만, 최적화를 위반하지 않는 코드를 사용하면 좋을 것이므로 그렇게하지 않을 것입니다.
(boost/C++ 0X 솔루션이 흥미 롭기 때문에 코드베이스에 부스트 또는 C++ 0X 의존성을 도입하는 것을 피하고 싶습니다. 좀 더 구형이 선호됩니다)
#include <new>
class Duck
{
public:
Duck() : _speed(0.0f), _quacking(false) {/* empty */}
virtual ~Duck() {/* empty */} // virtual only to demonstrate that this may not be a POD type
float _speed;
bool _quacking;
};
class Soup
{
public:
Soup() : _size(0), _temperature(0.0f) {/* empty */}
virtual ~Soup() {/* empty */} // virtual only to demonstrate that this may not be a POD type
int _size;
float _temperature;
};
enum {
TYPE_UNSET = 0,
TYPE_DUCK,
TYPE_SOUP
};
/** Tagged-union style variant class, can hold either one Duck or one Soup, but not both at once. */
class DuckOrSoup
{
public:
DuckOrSoup() : _type(TYPE_UNSET) {/* empty*/}
~DuckOrSoup() {Unset();}
void Unset() {ChangeType(TYPE_UNSET);}
void SetValueDuck(const Duck & duck) {ChangeType(TYPE_DUCK); reinterpret_cast<Duck*>(_data)[0] = duck;}
void SetValueSoup(const Soup & soup) {ChangeType(TYPE_SOUP); reinterpret_cast<Soup*>(_data)[0] = soup;}
private:
void ChangeType(int newType);
template <int S1, int S2> struct _maxx {enum {sz = (S1>S2)?S1:S2};};
#define compile_time_max(a,b) (_maxx< (a), (b) >::sz)
enum {STORAGE_SIZE = compile_time_max(sizeof(Duck), sizeof(Soup))};
char _data[STORAGE_SIZE];
int _type; // a TYPE_* indicating what type of data we currently hold
};
void DuckOrSoup :: ChangeType(int newType)
{
if (newType != _type)
{
switch(_type)
{
case TYPE_DUCK: (reinterpret_cast<Duck*>(_data))->~Duck(); break;
case TYPE_SOUP: (reinterpret_cast<Soup*>(_data))->~Soup(); break;
}
_type = newType;
switch(_type)
{
case TYPE_DUCK: (void) new (_data) Duck(); break;
case TYPE_SOUP: (void) new (_data) Soup(); break;
}
}
}
int main(int argc, char ** argv)
{
DuckOrSoup dos;
dos.SetValueDuck(Duck());
dos.SetValueSoup(Soup());
return 0;
}
이상한 코드입니다 ... –
이 코드를 GCC 팀에 제출 했습니까? 버그 보고서일까요? – curiousguy