Последнее обновление:2026-10-12
C++ ref и reference_wrapper¶
Глубокое понимание std::cref, std::ref и std::reference_wrapper в C++¶
При программировании на C++ иногда нужно передавать ссылки без копирования или использовать константные объекты там, где требуется ссылка. Для решения этих задач стандартная библиотека C++ предоставляет три полезных инструмента: std::cref, std::ref и std::reference_wrapper. В этой статье подробно рассматриваются назначения этих инструментов, их различия и практическое применение.
Кроме того, мы знаем, что в языке Rust часто реализуется метод Unwrap — а как реализовать его в C++?
Тут стоит обратиться к коду Apache arrow, где есть такой фрагмент:
std::optional<std::reference_wrapper<const TransportStatusDetail>>
TransportStatusDetail::Unwrap(const Status& status) {
std::shared_ptr<StatusDetail> detail = status.detail();
if (!detail) return std::nullopt;
if (detail->type_id() != kTypeId) return std::nullopt;
return std::cref(arrow::internal::checked_cast<const TransportStatusDetail&>(*detail));
}
После этого мы можем таким вызовом извлечь фактический TransportStatusDetail из Status.
Ниже рассмотрим всё это с нескольких сторон, а в конце приведём весь код Demo.
1. std::cref: создание константной ссылки¶
std::cref — это шаблонная функция для создания ссылки на константный объект. Она возвращает объект std::reference_wrapper, который можно использовать там, где нужна ссылка. Это особенно полезно при передаче параметров в функцию: она позволяет передавать константный объект без копирования, сохраняя семантику ссылки.
Пример:
#include <iostream>
#include <functional>
void printValue(const int& value) {
std::cout << "Value: " << value << std::endl;
}
int main() {
int number = 42;
auto crefNumber = std::cref(number);
printValue(crefNumber); // 使用常量引用传递参数
return 0;
}
2. std::ref: создание изменяемой ссылки¶
В отличие от std::cref, std::ref — это шаблонная функция для создания ссылки на изменяемый объект. Она возвращает объект std::reference_wrapper, который можно использовать там, где нужна ссылка, с возможностью изменять объект, на который она ссылается.
Пример:
#include <iostream>
#include <functional>
void modifyValue(int& value) {
value *= 2;
}
int main() {
int number = 42;
auto refNumber = std::ref(number);
modifyValue(refNumber); // 使用可修改的引用作为参数
std::cout << "Modified Value: " << number << std::endl;
return 0;
}
3. std::reference_wrapper: обёртка для ссылки¶
std::reference_wrapper — это шаблонный класс для обёртывания ссылок, позволяющий хранить их в контейнерах или передавать в виде ссылок. Он предоставляет синтаксис, похожий на ссылку, и совместим со стандартными контейнерами, поскольку контейнеры не могут напрямую хранить ссылки.
Пример:
#include <iostream>
#include <vector>
#include <functional>
int main() {
int number1 = 42;
int number2 = 73;
std::vector<std::reference_wrapper<int>> numbers = {std::ref(number1), std::ref(number2)};
for (auto& num : numbers) {
num.get() += 10; // 修改原始对象的值
}
std::cout << "Number 1: " << number1 << std::endl;
std::cout << "Number 2: " << number2 << std::endl;
return 0;
}
В этом примере std::reference_wrapper позволяет обернуть ссылки в контейнер, а затем через метод get() обращаться к значениям исходных объектов и изменять их.
4.Unwrap Demo¶
Здесь приведён конкретный фрагмент кода; полный код см. в материалах 知识星球.
std::optional<std::reference_wrapper<const TransportStatusDetail>> Unwrap(const Status& status) {
std::shared_ptr<StatusDetail> detail = status.detail();
if (!detail) return std::nullopt;
if (detail->type_id() != kTypeId) return std::nullopt;
return std::cref(static_cast<const TransportStatusDetail&>(*detail));
}
int main() {
// 创建 TransportStatusDetail 对象
std::shared_ptr<StatusDetail> transportDetail = std::make_shared<TransportStatusDetail>();
// 创建 Status 对象并传入 TransportStatusDetail 对象
Status status(transportDetail);
auto result = Unwrap(status);
if (result) {
const TransportStatusDetail& detail = result.value().get();
// 使用 detail 进行操作
std::cout << "TransportStatusDetail found." << std::endl;
} else {
std::cout << "No valid TransportStatusDetail found." << std::endl;
}
return 0;
}
Приглашаю вместе обсуждать C++那些事; больше проектов и материалов — добро пожаловать в 知识星球.
Похожие темы¶
- C++ чисто виртуальные функции и абстрактные классы | C++那些事
- C++ утверждения assert | C++那些事
- C++ битовые поля | C++那些事
- Реализация полиморфизма C++ на языке C | C++那些事
- C++ константы const и его модификация | C++那些事
- C++ всё семейство const | C++那些事
- C++ оператор разыменования * | C++那些事
- C++ инициализация и присваивание | C++那些事
- C++ возврат нескольких значений | C++那些事
- C++ ключевое слово mutable | C++那些事