Reference_wrapper в контейнерах C++

Рассмотрим следующий фрагмент:

#include <bits/stdc++.h>
using namespace std;

int main() {
    int x=3;
    int y=1;
    int z=2;
    cout<<(&x)<<' '<<(&y)<<' '<<(&z)<<endl;
    set<reference_wrapper<int>> a;
    a.insert(ref(x));
    a.insert(ref(y));
    a.insert(ref(z));
    for(const auto& i: a) cout<<i<<' '<<endl;
    y=10;
    for(const auto& i: a) cout<<i<<' ';
    return 0;
}

Что произойдет с базовым контейнером, если будет изменено свойство, используемое контейнером для сортировки?


Edit1: Судя по тому, что я могу попробовать, запустив код, порядок неправильный, но, поскольку он содержал ссылку, значение обновляется правильно. Итак, следует быть осторожным при использовании reference_wrapper внутри контейнеров (особенно там, где мутации могут привести к тому, что контейнер сделает недействительными его утверждения)?

вам удалось сломать инвариант. Ключи в std::set должны быть const. Как и почти во всем, есть способы обойти это ограничение, но в результате вы получите сломанный набор.

463035818_is_not_an_ai 09.07.2024 11:18

Что касается вашего «Edit1», пожалуйста, постарайтесь, чтобы вопрос был кратким. SO не похож на форум с постоянными дискуссиями. Нет необходимости читать вопрос, читать ответ и продолжать читать вопрос, чтобы понять, о чем здесь спрашивают.

463035818_is_not_an_ai 09.07.2024 11:20

«Это плохая практика…» основано на мнениях.

user12002570 09.07.2024 11:26

Если вы собираетесь использовать ссылочные оболочки, вы можете с таким же успехом хранить указатели, не принадлежащие (никакой реальной семантической разницы и проще в использовании). Большая проблема со ссылками (и указателями) заключается в том, что очень легко выстрелить себе в ногу. Представьте, что x, y, z являются локальными переменными функции, и вы возвращаете набор ссылок... Так что нет, это неплохая практика, но вам нужно быть осторожным. функция для сортировки указателей

Pepijn Kramer 09.07.2024 11:36

Обратите внимание, что вы, вероятно, не захотите использовать std::set, но std::vector<int*>

Pepijn Kramer 09.07.2024 11:37

@ 463035818_is_not_an_ai Очевидно, ключи следует сохранять константными. Я просто пытаюсь сказать, что, поскольку нет ограничений на тип ключа, можно столкнуться с этой проблемой. Более того, я пытаюсь проверить, следует ли считать использование reference_wrapper в контейнерах плохой практикой или следует быть осторожным?

Rupa 09.07.2024 11:45

это действительно интересная часть вопроса, на которую у меня тоже нет ответа. Обратите внимание, что std::set не предоставляет неконстантного доступа к элементам. std::set::iterator — постоянный итератор. Также обратите внимание, что на самом деле вы не изменяете элементы, а const, но вы изменяете объекты, на которые они ссылаются. Проблема в компараторе. Мне не известен какой-либо формализм, который требует, чтобы когда вы делаете auto x = comp(a,b);, что-то делали (но не вставляли и не удаляли элементы), auto y = comp(a,b); чтобы x и y были одинаковыми.

463035818_is_not_an_ai 09.07.2024 11:51

но кто-то другой знает :D

463035818_is_not_an_ai 09.07.2024 11:52

Понял, спасибо! @463035818_is_not_an_ai

Rupa 09.07.2024 12:06

Где вы учились #include <bits/stdc++.h>? Заблокируйте этот сайт. Сожгите эту книгу. Удалить этого друга из друзей. Изучите C++ по хорошей книге по C++.

Eljay 09.07.2024 13:12
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
10
83
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Что произойдет с базовым контейнером, если будет изменено свойство, используемое контейнером для сортировки?

Любое дальнейшее использование контейнера, требующее сравнения этого элемента, имеет неопределенное поведение, поскольку вы нарушаете это требование:

Для любых двух ключей k1 и k2 в одном контейнере вызов comp(k1, k2) всегда будет возвращать одно и то же значение.

[associative.reqmts.general]

Понял, спасибо! Как можно не вникать в эти проблемы? Следует ли нам избегать использования reference_wrapper в ключах ассоциативных контейнеров и неупорядоченных ассоциативных контейнеров?

Rupa 09.07.2024 12:10

Если ответ на вышеприведенный вопрос положительный, то разве стандарт не должен вообще позволять его создавать? Можно быть осторожным, но я думаю, что в большой кодовой базе гораздо проще столкнуться с этой проблемой.

Rupa 09.07.2024 12:13

@Рупа std::reference_wrapper это не волшебство. Создать подобные class может каждый. Ключевой принцип — не создавать висячие ссылки. Текущее состояние C++ не может помешать пользователю сделать это.

Red.Wave 09.07.2024 12:28

@Rupa Если бы стандарт блокировал std::reference_wrapper в наборах, то кто-то бы просто написал lib::reference_wrapper. Чтобы заблокировать это, вам придется запретить любой класс с любыми элементами данных-указателями. Вам просто нужно быть бдительным в отношении модификаций

Caleth 09.07.2024 12:28

@Red.Wave проблема здесь не висит, но, как правило, любое косвенное обращение, позволяющее изменить то, что сравнивает компаратор, имеет ту же проблему.

463035818_is_not_an_ai 09.07.2024 12:44

@463035818_is_not_an_ai постоянство — это лишь часть проблемы; предоставление правильного аргумента компаратора (например, компаратора адреса) может решить проблему постоянства. Неизбежную проблему висения невозможно решить, если не избегать reference_wrappper.

Red.Wave 09.07.2024 14:09

@Red.Wave но вопрос не в висящей ссылке. Конечно, могут быть проблемы, с которыми ОП еще не сталкивался, и важно знать о висячих ссылках. Ваш комментарий выглядит так, как будто отказ от висячих ссылок решит проблему с нарушенной сортировкой, но это не так. Возможно, я просто преувеличиваю, хотя именно это я и имею в виду.

463035818_is_not_an_ai 09.07.2024 14:12

@Red.Wave не ограничивается указателями и ссылками, член данных mutable также не подходит для формирования (части) сравнения

Caleth 09.07.2024 14:14

Компаратор @Caleth всегда должен быть определен, чтобы не полагаться на что-либо изменяемое. Но, как я упоминал ранее, хранение ссылок, не являющихся владельцами, например std::reference_wrapper, вызывает проблемы с висячими ссылками/указателями; Ссылки, не являющиеся владельцами, приветствуются только в немедленно выполняемых выражениях, и текущие спецификации ядра C++ не могут отличить их от остальных.

Red.Wave 09.07.2024 14:33

@Red.Wave или будьте осторожны с жизнью. В коде OP нет никаких висячих элементов, потому что символы int переживают набор

Caleth 09.07.2024 14:37

@Калет не посылай человека выполнять работу машины. Всякий раз, когда вы передаете ответственность человеку, появляются ошибки. Все эти идиомы программирования созданы для того, чтобы передать работу от человека к машине. В противном случае нет смысла использовать конструкции высокого уровня.

Red.Wave 09.07.2024 17:34

@Red.Wave, кажется, ты утверждаешь, что ссылки опасны. Согласен, но иногда нужна ссылочная семантика. Невыполнение требований также является ошибкой.

Caleth 09.07.2024 17:40

@Caleth Я утверждаю, что требования могут быть выполнены, но это не предотвращает ошибки. Широкое использование std::reference_wrapper — это бомба замедленного действия.

Red.Wave 09.07.2024 18:10

Другие вопросы по теме