簡體   English   中英

在 C++ 中為非 POD 類型創建 POD 包裝器

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM