使用 malloc 创建等效于 struct 的内存块

Using malloc to create a chunk of memory equivalent to struct

提问人:alf02 提问时间:11/17/2023 最后编辑:alf02 更新时间:11/19/2023 访问量:150

问:

我想使用 malloc 创建一个与结构等效的内存块,如下面的代码所示,但我收到警告“C6378 'pMyStructByMalloc' 可能是 '0'”,似乎无法让它工作。

    struct MyStruct
    {
        int a = 1;
        std::string s = "test";
        int b = 2;
    };
    MyStruct* pMyStruct = new MyStruct();

    int a = 1;
    int b = 2;
    std::string s = "test";

    int memorySize = sizeof(int) + sizeof(std::string) + sizeof(int);
    char* pMyStructByMalloc = (char*)malloc(memorySize);
    memcpy(pMyStructByMalloc, &a, sizeof(int)); // C6378 'pMyStructByMalloc' could be '0'
    memcpy((pMyStructByMalloc + sizeof(int)), &s, sizeof(std::string));
    memcpy((pMyStructByMalloc + sizeof(int) + +sizeof(std::string)), &b, sizeof(int));

有什么方法可以成功做到这一点吗?

使用 malloc 创建一个等同于 struct 的内存块。


附言。 好的,那么如果结构具有固定的长度并且是

struct MyStruct
{
  int a = 1;
  float s = 10.0f;
  int b = 2;
};

我正在尝试查看是否可以在不使用任何 MyStruct 的情况下“伪造”相同类型的内存并将内存块发送到某个低级函数。(假设我没有引用 MyStruct 代码,但只知道数据结构)


锅标 2

API如下所示

TheAPI(int32 bufferSize, void * data);

我通常这样做,

TheAPI(sizeof(MyStruct), pMyStruct);

但这次我想动态地做到这一点

TheAPI(memorySize , pMyStructByMalloc)

这样,我就可以尝试不同形式的记忆。(不同类型的固定大小结构)

C++语言

评论

6赞 Pepijn Kramer 11/17/2023
马洛克,梅姆皮......在现代 C++ 中不再常见(C++ 的整个思想是使用抽象,通常这些抽象已经根据需要接近于零开销)。更不用说使用这种技术,无论如何您都不会得到有效的结构。你有一个 std::string 成员,它的生存期(构造函数)永远不会被调用。那么,你真正想要实现的目标是什么?因为这种方法只是一个等待发生的事故(未定义的行为)
7赞 NathanOliver 11/17/2023
int memorySize = sizeof(int) + sizeof(std::string) + sizeof(int);是错误的。最有效的方法是int memorySize = sizeof(MyStruct);
7赞 NathanOliver 11/17/2023
也不要混用memcpystd::string
7赞 Eljay 11/17/2023
此代码错误地计算杆件偏移,因为它没有考虑填充。(从理论上讲,缓冲区也可能未对齐。 的复制它被打破了。这不是复制非 POD 对象的方法。memcpystd::string
4赞 molbdnilo 11/17/2023
malloc可以返回 null 指针。警告之所以存在,是因为您没有检查。(但这是你最不关心的问题。

答:

2赞 Pepijn Kramer 11/17/2023 #1

若要复制结构,请提供复制构造函数。 这将确保您的 std::string 也被正确复制,并将启动其生命周期。

#include <cassert>
#include <string>
#include <iostream>

struct MyStruct
{
    MyStruct() = default;
    ~MyStruct() = default;

    MyStruct(const MyStruct& rhs) :
        a{rhs.a},
        s{rhs.s},
        b{rhs.b}
    {
        std::cout << "Copy constructor";
    }

    // todo copy assignment, move constructor & move assignment
    
    int a = 1;
    std::string s = "test";
    int b = 2;
};

int main()
{
    MyStruct my_struct;
    auto copy_of_my_struct{my_struct};

    assert(copy_of_my_struct.a == 1);
    assert(copy_of_my_struct.s == std::string{"test"});
    assert(copy_of_my_struct.b == 2);
}

评论

4赞 NathanOliver 11/17/2023
无需手动提供复制构造函数或任何其他特殊成员函数。默认值将执行正确的操作。
0赞 Pepijn Kramer 11/18/2023
@NathanOliver 你是对的,这是为了明确说明复制可以做什么以及何时被称为;)
0赞 Red.Wave 11/18/2023
至少假装遵循规则 3 并提供 ed 赋值运算符。default
1赞 Ahmed AEK 11/18/2023 #2

如果你有一个缓冲区,并且希望它表示一个对象,你应该使用放置 new 运算符或 C++20 construct_at在特定位置调用构造函数/复制构造函数,这样可以保证对象的生存期被启动(并防止删除未构造的字符串),当你不再使用对象释放任何资源时,你还需要调用析构函数(或 C++20 destroy_at)。

#include <string>
#include <vector>

struct MyStruct
{
    int a = 1;
    std::string s = "test";
    int b = 2;
};

int main()
{
    std::vector<char> buffer = std::vector<char>(sizeof(MyStruct));
    MyStruct object1 = MyStruct();
    MyStruct* object2 = new (&buffer[0]) MyStruct{object1};
    object2->~MyStruct(); // destroy object to end its lifetime
    return 0;
}

请注意,对齐要求与任何标准类型对齐,因此可用于包含 ,但是如果您从其他地方(如 malloc)获取此内存,则需要确保内存正确对齐,否则操作员将向前推动指针以补偿对齐要求。std::vectorMyStructplacement new