Следующая короткая программа
#include <vector>
#include <iostream>
std::vector<int> someNums()
{
return {3, 5, 7, 11};
}
class Woop
{
public:
Woop(const std::vector<int>& nums) : numbers(nums) {}
void report()
{
for (int i : numbers)
std::cout << i << ' ';
std::cout << '\n';
}
private:
const std::vector<int>& numbers;
};
int main()
{
Woop woop(someNums());
woop.report();
}
имеет проблему со свисающими ссылками, о которой ни один компилятор не предупреждает. Проблема в том, что временные пользователи могут быть привязаны к const-refs, которые затем можно хранить. Тогда возникает вопрос: Есть ли способ избежать попадания в эту проблему? Предпочтительно тот, который не включает в себя жертву правильности или постоянное копирование больших объектов.
std::unique_ptr
для исключительного владения,std::shared_ptr
либо для совместного владения, либоstd::weak_ptr
, по крайней мере, для распознавания потерянных данных).-fsanitize=address
. Я не думаю, что есть лучшая практика, чтобы избежать этого без ущерба для производительности.Ответы:
В ситуации, когда какой-либо метод сохраняет ссылку после возврата, рекомендуется использовать
std::reference_wrapper
вместо обычной ссылки:Woop (std::vector<int> const &&) = delete;
для вашего метода:источник
Одним из способов сделать ваш класс менее уязвимым может быть добавление удаленного конструктора, который принимает правильную ссылку. Это остановит ваш экземпляр класса от привязок к временным.
Этот удаленный конструктор фактически сделает код O / P некомпилированным, что может быть за поведение, которое вы ищете?
источник
Я согласен с другими ответами и комментариями, которые вы должны тщательно продумать, если вам действительно нужно хранить ссылку в классе. И что, если вы это сделаете, вы, вероятно, захотите вместо этого неконстантный указатель на константный вектор (т.е.
std::vector<int> const * numbers_
).Однако, если это так, я считаю, что другие в настоящее время опубликованные ответы не имеют смысла. Они все показывают вам, как создать
Woop
эти ценности.Если вы можете быть уверены, что вектор, который вы передадите, переживет ваш
Woop
экземпляр, тогда вы можете явно отключить создание aWoop
из значения r. Это возможно с использованием синтаксиса C ++ 11:Теперь ваш пример кода больше не будет компилироваться. Компилятор с ошибкой, аналогичной:
PS: Вам, вероятно, нужен явный конструктор, см., Например, что означает явное ключевое слово? ,
источник
Чтобы предотвратить этот конкретный случай, вы можете либо взять указатель (так как
Weep(&std::vector<int>{1,2,3})
это не разрешено), либо вы можете использовать неконстантную ссылку, которая также будет иметь временную ошибку.Они по-прежнему не гарантируют, что значение остается действительным, но, по крайней мере, останавливает простейшую ошибку, не создает копию и не требует
nums
специального создания (например, какstd::shared_ptr
илиstd::weak_ptr
делает).std::scoped_lock
в качестве примера можно привести ссылку на мьютекс, а в случае, когда уникальное / общее / слабое ptr действительно не требуется. Часто этоstd::mutex
просто базовый член или локальная переменная. Вы все еще должны быть очень осторожны, но в этих случаях, как правило, легко определить продолжительность жизни.std::weak_ptr
это еще один вариант для не владеющих, но затем вы заставляете вызывающую сторону использоватьshared_ptr
(и, следовательно, также выделяете кучу), а иногда это не требуется.Если копия в порядке, это просто устраняет проблему.
Если
Woop
нужно взять в собственность, либо передать как r-значение и переместить (и полностью избежать проблем с указателями / ссылками), либо использовать,unique_ptr
если вы не можете переместить само значение или хотите, чтобы указатель оставался действительным.Или, если владение является общим, вы можете использовать его
shared_ptr
для всего, и оно будет удалено вместе с окончательной ссылкой, но это может сделать отслеживание жизненных циклов объекта очень запутанным при чрезмерном использовании.источник
Вы можете использовать
template programming
и,arrays
если вы хотите, чтобы объект, который содержитconst
контейнер. Благодаряconstexpr
конструктору иconstexpr arrays
вы добьетесьconst correctness
иcompile time execution
.Вот сообщение, которое может быть интересным: std :: move const vector
запустить код
Вывод:
источник
std::array
это гарантированно скопировать, даже если в противном случае будет доступен ход. Вдобавок ко всемуwooping1
иwooping2
не одного типа, что не идеально.