Какая часть языка запрещает изменять элементы std :: set - PullRequest
1 голос
/ 16 октября 2019

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

Рассмотрим следующую демонстрацию, которая создает std::set из int*, а затем пытается нарушить сортировку своих элементов:

#include <iostream>
#include <set>

int values[] = { 50, 40, 30, 20, 10 };

// Comparator that sorts by pointed value
struct comparator {
    bool operator()(const int* left, const int* right) const {
        return *left < *right;
    }
};

using my_set_t = std::set<int*, comparator>;

// Checks if each of the elements of `values` are in the set
void output(const my_set_t & foo)
{
    for (auto & x : values) {
        std::cout << x << ' ' << foo.count(&x) << '\n';
    }
    std::cout << std::endl;
}

int main()
{
    // Insert the address of each element of `values` into the set
    my_set_t foo;
    for (auto & x : values) {
        foo.emplace(&x);
    }

    output(foo);
    // Changing `values[1]` to zero should break the sorting of the set
    values[1] = 0;
    output(foo);
}

Вывод, который я получил:

50 1
40 1
30 1
20 1
10 1

50 1
0 0
30 0
20 0
10 0

Выражение values[1] = 0; эффективно изменяет один из ключей set косвенно. Это нарушает порядок и, следовательно, похоже, также нарушает count. Я предполагаю, что это также нарушит большинство других функций set.

Очевидно, что с кодом что-то не так. Насколько я могу судить, он следует всем правилам языка, и я не нарушаю никаких требований, которые я мог бы найти для функции сравнения или set. Но гарантии, предоставляемые set, тем не менее нарушены, а это значит, что я что-то упустил.

Ответы [ 2 ]

5 голосов
/ 16 октября 2019

В C ++ 17 есть [associative.reqmts] / 3:

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

Таким образом, ваш код имеет UB, поскольку он нарушает это требование.

0 голосов
/ 17 октября 2019

[Не очень политкорректное замечание: многие вещи не написаны в стандарте, и даже письменные вещи иногда неверны. Вы должны восполнить недостающие части, это более надежно, чем разбор точных слов.]

Все ассоциативные контейнеры (отсортированные или не отсортированные) основаны на аксиоматических требованиях.

Неявная основа состоит в том, что все предикаты / функторы, в которых есть аксиомы, являются математическими отношениями / функциями, иначе аксиомы ничего не значат. Итак, очевидно, что эти функции, как и компараторы, должны быть четко определены;это означает, что элементы в настоящее время в контейнере упорядочены .

Но это не имеет значения, если ваш контейнер пуст и вы меняете его функцию упорядочения. Вы также можете иметь полярный порядок, в котором вы упорядочиваете элементы в соответствии с углом, с произвольным срезом (минимальный угол по определению), и поворачиваете эту линию минимального угла, если вращение не проходит над элементами в контейнере.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...