[英]Creating a POD wrapper for non-POD types in C++
在我的代码中的某一时刻,我需要将一些参数作为 POD 结构传递(具体将数据复制到 CUDA常量memory)。 但我想通过用户定义的构造函数(无虚拟方法)传递更多“复杂”类型。
我想知道是否有任何问题(或更好的解决方案)做这样的事情来减轻 POD 约束(基本上使用 POD 结构至少与我感兴趣的 object 相同的大小作为真实事物的代理)。
#include <iostream>
#include <cstring>
// Meant to be used as a pointer to the Derived type.
template <class T>
struct PODWrapper
{
uint8_t data_[sizeof(T)];
const T& operator*() const { return *reinterpret_cast<const T*>(this); }
const T* operator->() const { return reinterpret_cast<const T*>(this); }
};
class NonPOD
{
protected:
float x_;
public:
NonPOD(float x) : x_(x) {}
NonPOD(const NonPOD& other) : x_(other.x_) {}
float x() const { return x_; }
float& x() { return x_; }
};
int main()
{
// initial value
NonPOD initial(10.0f);
//copying to pod wrapper
PODWrapper<NonPOD> pod;
std::memcpy(&pod, &initial, sizeof(NonPOD));
// accessing pod wrapper
NonPOD nonpod(*pod);
std::cout << nonpod.x() << std::endl;
return 0;
}
用例是能够声明一个结构 CUDA常量memory 具有任何类型(CUDA 期望 POD 类型)。 是这样的:
__constant__ PODWrapper<NonPOD> constantData;
我对此进行了测试,它似乎可以工作,但我特别担心 memory 问题,即使用 memcpy 到/从 PODWrapper 的“this”指针。
您的 PODWrapper 以三种方式表现出未定义的行为。 这是一个修复:
template <class T>
struct PODWrapper
{
alignas(T) std::byte data_[sizeof(T)];
const T& operator*() const { return *std::launder(reinterpret_cast<const T*>(data_)); }
const T* operator->() const { return std::launder(reinterpret_cast<const T*>(data_)); }
};
如果不对齐字节存储,则不能保证有足够的 memory。此外,您必须std::launder
memory 地址。
但是,最大的问题是在任何地方都没有创建 object 类型(除了initial
)。 memory 在那里,但就 C++ 而言,没有NonPOD
object 驻留在该 memory 中。您可以使用std::construct_at
和std::destory_at
来创建和销毁 object。
std::construct_at(pod.data_, initial);
请注意,object 与存储 object 的 memory 不同。 特别是对于非平凡的类型(顺便说一句,POD 的概念有些过时并且不再适用)。 有关详细信息,请参阅TrivialType 。
不要 memcopy 到data_
。 它不会创建 object 并且您仍将处于UB-land中。
访问权限对我来说很好。
当将“NonPOD”class 转换为“POD”class 非常简单时,我不确定为什么要制作包装器。
在此处查看 class 属性: https://en.cppreference.com/w/cpp/language/classes
您 class 仅缺少 2 个要求:
要解决这个问题,您需要删除非平凡的复制构造函数(如果需要,可以添加默认复制构造函数)并添加默认的平凡构造函数。 即这有效:
#include <iostream>
#include <type_traits>
class NonPOD
{
protected:
float x_;
public:
// Add trivial constructor
NonPOD() = default;
NonPOD(float x) : x_(x) {}
// Remove non-trivial copy constructor
//NonPOD(const NonPOD& other) : x_(other.x_) {}
float x() const { return x_; }
float& x() { return x_; }
};
int main()
{
std::cout << std::boolalpha;
std::cout << std::is_trivially_copyable<NonPOD>::value << std::endl;
std::cout << std::is_standard_layout<NonPOD>::value << std::endl;
std::cout << std::is_trivial<NonPOD>::value << std::endl;
std::cout << std::is_pod<NonPOD>::value << std::endl;
}
Output 是:
true
true
true
true
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.