#c #smart-pointers
#c #интеллектуальные указатели
Вопрос:
Я пытаюсь понять концепцию интеллектуальных указателей в C . У меня есть следующий фрагмент кода (модульный тест с использованием GoogleTest):
TEST(SHT35Sensor, ValidInstruction) {
auto sht35 = SampleSHT35::create();
sht35->add(22.4, 56.5);
char writeBuffer[100] = {0};
auto serial = std::make_unique<SampleSerial>("", writeBuffer, 0);
auto sensor = std::make_unique<SHT35Sensor>(0x03, serial.get(), sht35, 0);
auto actual = sensor->execute(Instruction(0, 0, Bytes("x02", 1)));
ASSERT_TRUE(actual);
}
Я хочу изолировать первые пять строк теста, чтобы их можно было использовать повторно. Я думал, что этого будет достаточно (и особенно это было бы правильно), чтобы сделать это:
std::shared_ptr<SHT35Sensor> prepare() {
auto sht35 = SampleSHT35::create();
sht35->add(22.4, 56.5);
char writeBuffer[100] = {0};
auto serial = std::make_unique<SampleSerial>("", writeBuffer, 0);
return std::make_shared<SHT35Sensor>(0x03, serial.get(), sht35, 0);
}
TEST(SHT35Sensor, ValidInstruction) {
auto sensor = prepare();
auto actual = sensor->execute(Instruction(0, 0, Bytes("x02", 1)));
ASSERT_TRUE(actual);
}
По сути, я переместил код в функцию, и вместо unique_ptr
этого я использовал shared_ptr
, чтобы иметь возможность разделить его между функцией, которая его создает, и вызывающей стороной.
Однако второй вариант приводит к ошибке сегментации при выполнении теста, что означает, что мое понимание интеллектуальных указателей неверно.
Что я делаю не так?
Комментарии:
1.
serial.get()
возвращает указатель, но не отделяет его от unique_ptr, поэтому, когда подготовка заканчивается, unique_ptr удаляет экземпляр SampleSerial, а shared_ptr содержит указатель на освобожденную память. Вы можете использоватьserial.release()
или напрямую использовать shared_ptr2. @marcinj: естественно, это было так просто. Не могли бы вы добавить свой комментарий к ответу?
3. FWIW, вы можете возвращать локальные функции
unique_ptr
, даже если их нельзя скопировать. Локальные функции будут перемещены, поскольку срок их действия истекает.4. Вы написали класс SHT35Sensor? Вы можете изменить его так, чтобы внутри него был shared_ptr или unique_ptr .
Ответ №1:
В вашем коде serial.get()
возвращает указатель, но не отсоединяет его от unique_ptr
, поэтому when prepare ends
— unique_ptr удаляет SampleSerial
экземпляр и shared_ptr
содержит указатель на освобожденную память. Вы можете использовать serial.release()
или использовать напрямую shared_ptr
.
Приведенный выше ответ предполагает, что SHT35Sensor
это будет обрабатывать время жизни SampleSerial
экземпляра. Но если это не так, тогда перейдите unique_ptr<SampleErial>
к SHT35Sensor
:
return std::make_shared<SHT35Sensor>(0x03, std::move(serial), sht35, 0);
Ваш SHT35Sensor
должен быть принят std::unique_ptr<SampleErial>
в качестве второго параметра — и передать его члену класса с помощью инициализации конструктора или еще раз std::move
.
Я бы предпочел второе решение, поскольку никакой пустой указатель не будет принят SHT35Sensor
— и это хорошо.
Комментарии:
1. Это решение, вероятно, приведет к утечке памяти. Кто тогда будет удалять этот
release
общий указатель?2. @Evg вы правы, я отвечу udpdate (но, может быть, SHT35Sensor делает это, кто знает:-))
3. Если
SHT35Sensor
это сделать, исходный код, скорее всего, завершится сбоем из-за двойного обнаружения.