我的容器需要存储有关其元素的一些信息。通常,我将它与元素分开存储。但是,我想通过在元素结构类型中专用一个字段供外部使用,为用户提供节省内存的可能性。 E.g:
struct MyStuff
{
int foo;
char bar;
mutable char dedicated_for_external_use; // Because of alignment, this field
// won't increase sizeof (MyStuff)
};
这里的想法是除了元素的容器之外,任何东西都不能访问该字段。由于容器存储副本(非常类似于std::vector
),因此如果您将任何给定值x
添加到多个容器中,则不会有问题。
如果可能的话,您如何设计一个接口,以满足以下要求?
MyStuff
启用此优化,则可以使用3行代码而不是25行代码。另一方面,内部并发症并不重要。foo_bar
,那么存在一个很小的可能性,这个字段存在是出于完全不相关的原因(我认为鸭子输入根本不适用于C ++)。更好的方法是检查类型是否从我的库继承标记类ProvidesExternalUseField
,因为这不是偶然的。修改
我知道Boost.Intrusive,但我想要的是不同的东西。如果我这样做并使用单个char
字段创建一个钩子类,在许多情况下它不能用于节省内存。如果继承类型的第一个字段为int
,则char
字段将填充为4个字节。即你经常需要复杂的类型内部知识才能“挤压”这样的外部使用字段,但继承并没有真正提供它:
struct hooks { mutable char dedicated_for_external_use; };
struct MyStuff : hooks
{
int foo;
char bar;
};
此处,MyStuff
的大小为12个字节,而不是8个。
答案 0 :(得分:0)
对于数据结构从标记接口派生的情况,您可以使用部分模板特化。
假设您的标记接口类如下所示:
class ProvidesExternalUseField
{
public:
char GetExtraField () { return 0; }
void SetExtraField (char newVal) {}
};
它不是虚拟的目的:我们不想为此添加一个数据类的vtable指针。
现在让我们实现一个简单的容器类:
template <class T>
class Container
{
public:
char GetExtraValue ()
{
return 0; // here we cannot know if T is derived from the marker
}
private:
T m_t;
};
以下是我们如何改变以区分这两种情况:
template <class T, bool DoesTProvideExternalUseField>
class ContainerImpl
{
public:
char GetExtraValue () { return 0; }
private:
T m_t;
};
template <class T>
class ContainerImpl<T, true>
{
public:
char GetExtraValue () { return m_t.GetExtraField(); }
private:
T m_t;
};
template <class T>
class Container: public ContainerImpl<T,
boost::is_base_of<ProvidesExternalUseField,T>::value>
{
};
现在你可以像这样定义结构:
struct A
{
int m_intVal;
};
struct B: public ProvidesExternalUseField
{
char GetExtraField () { return m_extraField; }
void SetExtraField (char newVal) { m_extraField = newVal; }
int m_intVal;
char m_charVal;
char m_extraField;
};
以完全相同的方式使用容器类:
Container<A> a;
Container<B> b;
您还可以使用poiter-to-member作为模板参数,在标记界面中进一步自动化(模板化)getter和setter。