4

我正在寻找一种方法来使用 unique_ptr 来分配一个结构,该结构包含一个 char 数组,其中有多个字节动态设置以支持不同类型的消息。

假设:

struct MyMessage
{
    uint32_t      id;
    uint32_t      data_size;
    char          data[4];
};

如何将下面的 send_message() 转换为使用智能指针?

void send_message(void* data, const size_t data_size)
{
    const auto message_size = sizeof(MyMessage) - 4 + data_size;
    const auto msg = reinterpret_cast<MyMessage*>(new char[message_size]);

    msg->id = 3;
    msg->data_size = data_size;
    memcpy(msg->data, data, data_size);

    // Sending the message
    // ...

    delete[] msg;
}

我尝试使用以下代码使用智能点无法编译:

const auto message_size = sizeof(MyMessage) - 4 + data_size;
const auto msg = std::unique_ptr<MyMessage*>(new char[message_size]);

下面是一个完整的工作示例:

#include <iostream>
#include <iterator>
#include <memory>

using namespace std;

struct MyMessage
{
    uint32_t      id;
    uint32_t      data_size;
    char          data[4];
};

void send_message(void* data, const size_t data_size)
{
    const auto message_size = sizeof(MyMessage) - 4 + data_size;
    const auto msg = reinterpret_cast<MyMessage*>(new char[message_size]);
    if (msg == nullptr)
    {
        throw std::domain_error("Not enough memory to allocate space for the message to sent");
    }
    msg->id = 3;
    msg->data_size = data_size;
    memcpy(msg->data, data, data_size);

    // Sending the message
    // ...

    delete[] msg;
}

struct MyData
{
    int  page_id;
    char point_name[8];
};

void main()
{
    try
    {
        MyData data{};
        data.page_id = 7;
        strcpy_s(data.point_name, sizeof(data.point_name), "ab332");
        send_message(&data, sizeof(data));
    }
    catch (std::exception& e)
    {
        std::cout << "Error: " << e.what() << std::endl;
    }
}
4

2 回答 2

2

您传递给的数据类型delete[]需要与new[]返回的内容相匹配。在您的示例中,您正在new[]ing 一个char[]数组,但随后正在delete[]ing 一个MyMessage对象。那不管用。

简单的解决方法是更改​​此行:

delete[] msg;

为此:

delete[] reinterpret_cast<char*>(msg);

但是,您应该使用智能指针来为您管理内存删除。但是,您提供的指针std::unique_ptr需要与您指定的模板参数相匹配。在您的示例中,您声明了 a std::unique_ptr,其模板参数为MyMessage*,因此构造函数期望 a MyMessage**,但您将其传递给 a char*

试试这个:

// if this struct is being sent externally, consider
// setting its alignment to 1 byte, and setting the
// size of the data[] member to 1 instead of 4...
struct MyMessage
{
    uint32_t      id;
    uint32_t      data_size;
    char          data[4];
};

void send_message(void* data, const size_t data_size)
{
    const auto message_size = offsetof(MyMessage, data) + data_size;

    std::unique_ptr<char[]> buffer = std::make_unique<char[]>(message_size);
    MyMessage *msg = reinterpret_cast<MyMessage*>(buffer.get());    

    msg->id = 3;
    msg->data_size = data_size;
    std::memcpy(msg->data, data, data_size);

    // Sending the message
    // ...
}

或这个:

using MyMessage_ptr = std::unique_ptr<MyMessage, void(*)(MyMessage*)>;

void send_message(void* data, const size_t data_size)
{
    const auto message_size = offsetof(MyMessage, data) + data_size;

    MyMessage_ptr msg(
        reinterpret_cast<MyMessage*>(new char[message_size]),
        [](MyMessage *m){ delete[] reinterpret_cast<char*>(m); }
    );

    msg->id = 3;
    msg->data_size = data_size;
    std::memcpy(msg->data, data, data_size);

    // Sending the message
    // ...
}
于 2018-05-02T22:27:08.420 回答
0

这应该可以,但是仍然不清楚msg->data越界访问是否合法(但至少它并不比原始代码中的最差):

const auto message_size = sizeof(MyMessage) - ( data_size < 4 ? 0 : data_size - 4 );
auto rawmsg = std::make_unique<char[]>( message_size );
auto msg = new (rawmsg.get()) MyMessage;
于 2018-05-02T21:32:13.927 回答