安置新的vs海湾合作委员会4.4.3严格的混淆规则
-
27-09-2019 - |
题
我已经得到了一些代码,我已经成功地使用一些多年实行的"变体类型的对象";就是说,C++的对象,可以举行一个价值观的各种类型,但只使用了(大约)尽可能多的内存作为最大的可能类型。代码类似于在精神的一种标记的联盟,除了它支持非POD数据类型。它完成这魔法通过使用炭缓冲区、安置新的/删除,并reinterpret_cast<>.
我最近试图编写这些代码下的海湾合作委员会4.4.3(与O3和墙壁),并且得到了许多警告这样的:
warning: dereferencing type-punned pointer will break strict-aliasing rules
从我读,这是一个指示,海湾合作委员会的新的优化可能会产生'越野车的代码,我显然愿,以避免。
我已经粘贴'玩具'我的代码如下;有什么我可以做我的代码,使它更加安全的在海湾合作委员会4.4.3,同时仍然支持非POD数据的类型?我知道,作为最后的手段,我总是可以汇编的代码-fno-严格的混淆,但这将是很好的代码就不断在优化所以我宁愿不这样做。
(注意,我想避免引入一个增强或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;
}
解决方案
好吧,你可以做到这一点,如果你愿意来存储额外void*。我重新格式化的样品位,因此它是对我来说更容易的工作。看看这个,看看它是否适合你的需要。此外,请注意,我提供了一些样品,所以你可以添加一些模板,这将有助于实用性。他们可以延伸得更多,但是,应该给你一个很好的想法。
还有一些输出的东西来帮你看看怎么回事。
还有一件事,我假设你知道你需要提供适当的复制构造函数和分配运营但是,这并不是症结所在的这个问题。
我g++版本信息:
g++版本 g++(SUSE Linux)4.5.0中20100604[海湾合作委员会-4_5支修订160292]
#include <new>
#include <iostream>
class Duck
{
public:
Duck(float s = 0.0f, bool q = false) : _speed(s), _quacking(q)
{
std::cout << "Duck::Duck()" << std::endl;
}
virtual ~Duck() // virtual only to demonstrate that this may not be a POD type
{
std::cout << "Duck::~Duck()" << std::endl;
}
float _speed;
bool _quacking;
};
class Soup
{
public:
Soup(int s = 0, float t = 0.0f) : _size(s), _temperature(t)
{
std::cout << "Soup::Soup()" << std::endl;
}
virtual ~Soup() // virtual only to demonstrate that this may not be a POD type
{
std::cout << "Soup::~Soup()" << std::endl;
}
int _size;
float _temperature;
};
enum TypeEnum {
TYPE_UNSET = 0,
TYPE_DUCK,
TYPE_SOUP
};
template < class T > TypeEnum type_enum_for();
template < > TypeEnum type_enum_for< Duck >() { return TYPE_DUCK; }
template < > TypeEnum type_enum_for< Soup >() { return 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), _data_ptr(_data) {/* empty*/}
~DuckOrSoup() {Unset();}
void Unset() {ChangeType(TYPE_UNSET);}
void SetValueDuck(const Duck & duck)
{
ChangeType(TYPE_DUCK);
reinterpret_cast<Duck*>(_data_ptr)[0] = duck;
}
void SetValueSoup(const Soup & soup)
{
ChangeType(TYPE_SOUP);
reinterpret_cast<Soup*>(_data_ptr)[0] = soup;
}
template < class T >
void set(T const & t)
{
ChangeType(type_enum_for< T >());
reinterpret_cast< T * >(_data_ptr)[0] = t;
}
template < class T >
T & get()
{
ChangeType(type_enum_for< T >());
return reinterpret_cast< T * >(_data_ptr)[0];
}
template < class T >
T const & get_const()
{
ChangeType(type_enum_for< T >());
return reinterpret_cast< T const * >(_data_ptr)[0];
}
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 * _data_ptr;
};
void DuckOrSoup :: ChangeType(int newType)
{
if (newType != _type)
{
switch(_type)
{
case TYPE_DUCK: (reinterpret_cast<Duck*>(_data_ptr))->~Duck(); break;
case TYPE_SOUP: (reinterpret_cast<Soup*>(_data_ptr))->~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)
{
Duck sample_duck; sample_duck._speed = 23.23;
Soup sample_soup; sample_soup._temperature = 98.6;
std::cout << "Just saw sample constructors" << std::endl;
{
DuckOrSoup dos;
std::cout << "Setting to Duck" << std::endl;
dos.SetValueDuck(sample_duck);
std::cout << "Setting to Soup" << std::endl;
dos.SetValueSoup(sample_soup);
std::cout << "Should see DuckOrSoup destruct which will dtor a Soup"
<< std::endl;
}
{
std::cout << "Do it again with the templates" << std::endl;
DuckOrSoup dos;
std::cout << "Setting to Duck" << std::endl;
dos.set(sample_duck);
std::cout << "duck speed: " << dos.get_const<Duck>()._speed << std::endl;
std::cout << "Setting to Soup" << std::endl;
dos.set(sample_soup);
std::cout << "soup temp: " << dos.get_const<Soup>()._temperature << std::endl;
std::cout << "Should see DuckOrSoup destruct which will dtor a Soup"
<< std::endl;
}
{
std::cout << "Do it again with only template get" << std::endl;
DuckOrSoup dos;
std::cout << "Setting to Duck" << std::endl;
dos.get<Duck>() = Duck(42.42);
std::cout << "duck speed: " << dos.get_const<Duck>()._speed << std::endl;
std::cout << "Setting to Soup" << std::endl;
dos.get<Soup>() = Soup(0, 32);
std::cout << "soup temp: " << dos.get_const<Soup>()._temperature << std::endl;
std::cout << "Should see DuckOrSoup destruct which will dtor a Soup"
<< std::endl;
}
std::cout << "Get ready to see sample destructors" << std::endl;
return 0;
}
其他提示
我会写的代码就像这样:
typedef boost::variant<Duck, Soup> DuckOrSoup;
但我想每个人都有自己的味道。
顺便说一句,你的代码是越野车,你还没有采取护理的可能的调整问题,不能只是把一个目在任何一点在存储器中,有一个制约因素方面,其改变,与每一个类型。C++0x,还有就是 alignof
关键词得到它,其他一些公用事业,以获得对准储存。
我已经成功说服海湾合作委员会(4.2.4,运行与 -Wstrict-aliasing=2
)不要抱怨通过使用 void *
暂时的,即。
void SetValueDuck(const Duck & duck) {ChangeType(TYPE_DUCK); void *t=&_data; reinterpret_cast<Duck*>(t)[0] = duck;}
我仍然无法理解的需要或使用这个但是 g++4.4.3与O3墙与以下修补程序。如果它的作品,你能分享使用的情况下,为什么你需要这个吗?
class DuckOrSoup
{
public:
DuckOrSoup() : _type(TYPE_UNSET) {_duck = NULL; _soup = NULL;/* empty*/}
~DuckOrSoup() {Unset();}
void Unset() {ChangeType(TYPE_UNSET);}
void SetValueDuck(const Duck & duck) {ChangeType(TYPE_DUCK); _duck = new (&_data[0])Duck (duck); }
void SetValueSoup(const Soup & soup) { ChangeType(TYPE_SOUP); _soup = new (&_data[0])Soup (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
Duck* _duck;
Soup* _soup;
};
void DuckOrSoup :: ChangeType(int newType)
{
if (newType != _type)
{
switch(_type)
{
case TYPE_DUCK:
_duck->~Duck();
_duck = NULL;
break;
case TYPE_SOUP:
_soup->~Soup();
_soup = NULL;
break;
}
_type = newType;
switch(_type)
{
case TYPE_DUCK: _duck = new (&_data[0]) Duck(); break;
case TYPE_SOUP: _soup = new (&_data[0]) Soup(); break;
}
}
}