[英]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.