Это, конечно, не совсем корректное поведение в целом.
Между окончанием выполнения функционального объекта и окончанием вызова operator()
член operator()
выполняется на удаленный объект. Если реализация читает или записывает через this
, что вполне разрешено делать, тогда вы получите чтение или запись удаленного объекта.
Более конкретно, объект был просто удален этим очень ничто, поэтому маловероятно, чтобы какой-либо поток действительно обходил его использование между удалением и чтением / записью, или он был неотображаем, поэтому вряд ли это действительно вызовет проблемы в простой программе. Кроме того, существует небольшая очевидная причина для реализации, чтобы читать или записывать в this
после ее возвращения.
Однако Valgrind вполне корректен, что любое такое чтение или запись будет очень недействительный и в некоторых случаях может привести к случайным сбоям или повреждению памяти. Легко предположить, что между удалением this
и гипотетическим чтением / записью этот поток был предварительно упущен, а другой поток назначен и использовал эту память. В качестве альтернативы, распределитель памяти решил, что у него достаточно кэшированной памяти такого размера, и сразу же освободил этот сегмент для ОС. Это отличный кандидат на Гейзенбуг, поскольку условия его возникновения будут относительно редкими и очевидны только в реальных сложных системах исполнения, а не в тривиальных тестовых программах.
Вы могли бы избежать этого , если вы можете доказать, что чтения или записи нет после завершения объекта функции. Это в основном означает гарантию реализации std::function<Sig>::operator()
.
Редактировать:
Ответ Матса Петерсона вызывает интересный вопрос. GCC, похоже, реализовал лямбда, выполнив что-то вроде этого:
struct lambda { std::function<void()>* f; };
void lambda_operator(lambda* l) {
l->f->~std::function<void()>();
::operator delete(l->f);
}
Как вы можете видеть, вызов operator delete
выполняет загрузку с l
после того, как он только что был удален, что точно описанный выше сценарий. Я на самом деле не уверен, что правила модели памяти C ++ 11 говорят об этом, я бы подумал, что это незаконно, но не обязательно. Он не может быть определен в любом случае. Если это не является незаконным, вы определенно ввернуты.
Тем не менее Clang, похоже, сгенерирует этот оператор:
void lambda_operator(lambda* l) {
auto f = l->f;
f->~std::function<void()>();
::operator delete(f);
}
Здесь, когда l
удален, это не имеет значения потому что f
был скопирован в локальное хранилище.
В определенной степени это окончательно отвечает на ваш вопрос. GCC абсолютно загружает из памяти лямбда после ее удаления. Является ли это стандартным или нет, я не уверен. Вы определенно можете обойти это, используя определенную пользователем функцию. Тем не менее, проблема с реализацией std :: function, выполняющей загрузку или сохранение в хранилище до this
.
Это на самом деле очень просто. Сначала определите структуру для вашего элемента словаря, например, так:
struct Item: Codable {
let cd_sala: String
let nm_sala: String
}
Затем создайте экземпляр для JSONDecoder:
let decoder = JSONDecoder()
и используйте его для декодирования данных
[112 ] Dictionary<Int, Item>
относится к классу хеш-таблицы по умолчанию (ключ, значение), который дает вам доступ к элементу, например:
// outputs "Treinamento de Teste"
print(object[1]!.nm_sala)