c ++ 11 — объект C ++, содержащий массив char с использованием unique_ptr

Я ищу способ использовать 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;
}

Моя попытка использовать Smart Point с использованием приведенного ниже кода не компилируется:

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

Решение

Тип данных, который вы передаете delete[] должен соответствовать тому, что new[] возвращается. В вашем примере вы new[]в char[] массив, но потом delete[]в MyMessage объект вместо Это не будет работать.

Простым решением было бы изменить эту строку:

delete[] msg;

На это вместо этого:

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

Тем не менее, вы должны использовать умный указатель, чтобы управлять удалением памяти для вас. Но указатель, который вы даете std::unique_ptr должен соответствовать указанному параметру шаблона. В вашем примере вы объявляете std::unique_ptr чей параметр шаблона MyMessage*поэтому конструктор ожидает MyMessage**, но вы передаете это 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
// ...
}
2

Другие решения

Это должно работать, но все еще не ясно, если доступ 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;
0

По вопросам рекламы [email protected]