直接访问唯一 class 数据成员
Direct access to unique class data member
我有一个 class,它有一个唯一的 public 数据成员,它是一个内置类型:
class foo {
public:
int data;
foo(int dataIn) : data(dataIn) {}
virtual ~foo() {}
// Some other class methods
protected:
// Some internal helper class methods
};
在另一个class中,我想使用memcpy
方法:
template<typename T>class bar {
protected:
T data;
public:
bar() {}
virtual ~bar() {}
void read(unsigned char* readBuff, const std::size_t &readSize) {
// Some stuff
std::memcpy(readBuff, &(this->data), readSize);
// Some stuff
}
};
想法是 bar
当 T
是内置类型或 foo
的实例时可用。
但是 T 是 foo
,因此 bar
中的 data
是一个 foo
实例,我是否确保从 &(this->data)
指向的元素读取将 data
在 foo
?
当我运行这个:
foo x(12);
std::cout << sizeof(foo);
我得到4
,所以foo好像正好是一个int的大小,所以我自然会认为直接reading/writing到x
即使不指定x.data
会写入数据。是真的吗?
我需要与 C++11 兼容。
没有
对于带有虚函数的class,通常编译器会在class的开头插入一些元数据。您不能假定实例的地址也是其第一个成员的地址。
你可以用if constexpr
来区分这2种情况:
if constexpr ( std::is_same_v<std::decay_t<T>, foo> ) {
std::memcpy(readBuff, &(this->data.data), readSize);
} else {
std::memcpy(readBuff, &(this->data), readSize);
}
没有
具有虚拟成员的任意类型的布局是实现定义的。不能保证 data
在 foo.
的偏移量为 0 处
您可以将 bar
完全专门化为 foo
。
template<>class bar<foo> {
protected:
foo data;
public:
bar() {}
virtual ~bar() {}
void write(unsigned char* readBuff, const std::size_t &readSize) {
// Some stuff
std::memcpy(readBuff, &(this->data.data), readSize);
// Some stuff
}
};
如果bar
其余部分的重复有问题,你可以写一个辅助模板
template<typename T> bar_helper
{
void* operator()(T & data) { return &data; }
}
template<> bar_helper<foo>
{
void* operator()(foo & data) { return &data.data; }
}
template<typename T>
void bar<T>::write(unsigned char* readBuff, const std::size_t &readSize) {
// Some stuff
bar_helper<T> helper;
std::memcpy(readBuff, helper(this->data), readSize);
// Some stuff
}
经过几次尝试,我找到了另一种实现它的方法,而不必像@Caleth 的解决方案(虽然非常好)那样在 read() 中实例化一个新的 helper
对象,所以哪个应该更好表现:
class foo {
public:
int data;
foo(int dataIn) : data(dataIn) {}
virtual ~foo() {}
// Some other class methods
protected:
// Some internal helper class methods
};
template<bool ISFOO> struct IsFoo_ {
enum {
IS_FOO_ = ISFOO
};
};
template<typename T>class bar {
protected:
T data;
public:
bar() {}
virtual ~bar() {}
struct CRV {
enum {
USES_FOO = std::is_same<T, foo>::value
};
};
void* getCopyable() {
return getCopyable_<CRV::USES_FOO>();
}
void read(unsigned char* readBuff, const std::size_t &readSize) {
// Some stuff
std::memcpy(readBuff, this->getCopyable(), readSize);
// Some stuff
}
private:
// Caller method
template<bool ISFOO> inline void* getCopyable_() {
return getCopyable_(IsBitVector_<ISFOO>());
}
// Generic method
template<bool ISFOO> inline void* getCopyable_(IsFoo_<ISFOO>) {
return nullptr;
}
// Specializations
inline void* getCopyable_(IsFoo_<true>) {
return reinterpret_cast<void*>(&(this->data.data));
}
inline void* getCopyable_(IsFoo_<false>) {
return reinterpret_cast<void*>(&(this->data));
}
};
我有一个 class,它有一个唯一的 public 数据成员,它是一个内置类型:
class foo {
public:
int data;
foo(int dataIn) : data(dataIn) {}
virtual ~foo() {}
// Some other class methods
protected:
// Some internal helper class methods
};
在另一个class中,我想使用memcpy
方法:
template<typename T>class bar {
protected:
T data;
public:
bar() {}
virtual ~bar() {}
void read(unsigned char* readBuff, const std::size_t &readSize) {
// Some stuff
std::memcpy(readBuff, &(this->data), readSize);
// Some stuff
}
};
想法是 bar
当 T
是内置类型或 foo
的实例时可用。
但是 T 是 foo
,因此 bar
中的 data
是一个 foo
实例,我是否确保从 &(this->data)
指向的元素读取将 data
在 foo
?
当我运行这个:
foo x(12);
std::cout << sizeof(foo);
我得到4
,所以foo好像正好是一个int的大小,所以我自然会认为直接reading/writing到x
即使不指定x.data
会写入数据。是真的吗?
我需要与 C++11 兼容。
没有
对于带有虚函数的class,通常编译器会在class的开头插入一些元数据。您不能假定实例的地址也是其第一个成员的地址。
你可以用if constexpr
来区分这2种情况:
if constexpr ( std::is_same_v<std::decay_t<T>, foo> ) {
std::memcpy(readBuff, &(this->data.data), readSize);
} else {
std::memcpy(readBuff, &(this->data), readSize);
}
没有
具有虚拟成员的任意类型的布局是实现定义的。不能保证 data
在 foo.
您可以将 bar
完全专门化为 foo
。
template<>class bar<foo> {
protected:
foo data;
public:
bar() {}
virtual ~bar() {}
void write(unsigned char* readBuff, const std::size_t &readSize) {
// Some stuff
std::memcpy(readBuff, &(this->data.data), readSize);
// Some stuff
}
};
如果bar
其余部分的重复有问题,你可以写一个辅助模板
template<typename T> bar_helper
{
void* operator()(T & data) { return &data; }
}
template<> bar_helper<foo>
{
void* operator()(foo & data) { return &data.data; }
}
template<typename T>
void bar<T>::write(unsigned char* readBuff, const std::size_t &readSize) {
// Some stuff
bar_helper<T> helper;
std::memcpy(readBuff, helper(this->data), readSize);
// Some stuff
}
经过几次尝试,我找到了另一种实现它的方法,而不必像@Caleth 的解决方案(虽然非常好)那样在 read() 中实例化一个新的 helper
对象,所以哪个应该更好表现:
class foo {
public:
int data;
foo(int dataIn) : data(dataIn) {}
virtual ~foo() {}
// Some other class methods
protected:
// Some internal helper class methods
};
template<bool ISFOO> struct IsFoo_ {
enum {
IS_FOO_ = ISFOO
};
};
template<typename T>class bar {
protected:
T data;
public:
bar() {}
virtual ~bar() {}
struct CRV {
enum {
USES_FOO = std::is_same<T, foo>::value
};
};
void* getCopyable() {
return getCopyable_<CRV::USES_FOO>();
}
void read(unsigned char* readBuff, const std::size_t &readSize) {
// Some stuff
std::memcpy(readBuff, this->getCopyable(), readSize);
// Some stuff
}
private:
// Caller method
template<bool ISFOO> inline void* getCopyable_() {
return getCopyable_(IsBitVector_<ISFOO>());
}
// Generic method
template<bool ISFOO> inline void* getCopyable_(IsFoo_<ISFOO>) {
return nullptr;
}
// Specializations
inline void* getCopyable_(IsFoo_<true>) {
return reinterpret_cast<void*>(&(this->data.data));
}
inline void* getCopyable_(IsFoo_<false>) {
return reinterpret_cast<void*>(&(this->data));
}
};