@ он хорошо, я сделал это сам. Глядя на ваш отзыв о

тим, у меня есть подвижный и не копируемый объект, и у меня есть многоиндексный массив boost с индексом random_access. Мне нужно переместить мой объект за пределы массива, но я не могу найти метод, который бы дал мне ссылку на rvalue / lvalue вдокументация, Я могу видеть толькоfront() что дает мне постоянную ссылку иpop_front() который стирает элемент, но ничего не возвращает. Так есть ли способ вывести элемент из мультииндекса буста?

Ответы на вопрос(2)

поскольку они могут оставлять элементы в состоянии, которое нарушает инварианты, размещенные в них различными индексами.

Самое близкое, что вы можете сделать, это использоватьmodify:

moveonly pop_front(Table& table) {
    moveonly extracted;

    auto it = table.begin();
    if (it == table.end())
        throw std::logic_error("pop_front");

    if (table.modify(it, [&](moveonly& v) { extracted = std::move(v); })) {
        table.erase(it);
    }

    return extracted;
}

Обратите внимание, чтоmodify несет расходы по проверке всех индексов и может потерпеть неудачу. К счастью, если это не удается, эффект заключается в том, чтоiterator стерто:

Эффекты: Вызывает mod (e), где e - элемент, на который указывает position, и переставляет * position во все индексы multi_index_container. Перестановка последовательных индексов не меняет положение элемента относительно индекса; перестановка по другим показателям может или не может быть успешной.Если перестановка не удалась, элемент стирается.Постусловия: действительность позиции сохраняется, если операция завершается успешно.

А вот и живая демонстрация:

Жить на Колиру

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <iostream>

struct moveonly {
    int x;
    moveonly(int x = -1) noexcept : x(x) {}
    moveonly(moveonly&& o) noexcept : x(o.x) { o = {}; }
    moveonly& operator=(moveonly o) noexcept { using std::swap; swap(x, o.x); return *this; }
};

static_assert(not std::is_copy_constructible<moveonly>{}, "moveonly");

namespace bmi = boost::multi_index;
using Table   = bmi::multi_index_container<moveonly,
    bmi::indexed_by<
        bmi::random_access<bmi::tag<struct _ra> >
    > >;

template <typename Container>
void dump(std::ostream& os, Container const& c) { 
    for (auto& r: c) os << r.x << " ";
    os << "\n";
}

moveonly pop_front(Table& table) {
    moveonly extracted;

    auto it = table.begin();
    if (it == table.end())
        throw std::logic_error("pop_front");

    if (table.modify(it, [&](moveonly& v) { extracted = std::move(v); })) {
        table.erase(it);
    }

    return extracted;
}

int main() {
    Table table;

    table.push_back({1});
    table.push_back({2});
    table.push_back({3});

    dump(std::cout << "table before: ", table);

    std::cout << "Extracted: " << pop_front(table).x << "\n";

    dump(std::cout << "table after: ", table);
}

Какие отпечатки:

table before: 1 2 3 
Extracted: 1
table after: 2 3 
 Slava06 сент. 2017 г., 22:47
Кстати, еслиmodify возвращает false, вероятно, он должен просто вернуться, а не выдавать исключение. как элемент будет удален в этом случае (что нам действительно нужно)
 Slava06 сент. 2017 г., 22:45
Я понимаю, почему объект не может быть изменен. Я не понимаю, почему нет способа извлечь элемент из массива, а не просто удалить его. Этот метод - довольно плохой обходной путь, так как он может быть излишне дорогостоящим (перестановка индексов может быть дорогостоящим), а также накладывает ненужные требования на элемент.
 sehe06 сент. 2017 г., 22:55
@Slava Re: второй комментарий; Да уж. В этой конкретной операции это выглядит нормально. Когда я писал код, я не до конца осознавал значение полной стабильности итератора во всей операции. Обновил ответ.
 Joaquín M López Muñoz07 сент. 2017 г., 13:55
@ он хорошо, я сделал это сам. Глядя на ваш отзыв оextract/merge.
 Slava06 сент. 2017 г., 23:13
stable_vector может быть ближе кrandom_access Индекс, но, возможно, не то, что мне нужно. Я пытаюсь реализовать приоритетную очередь с возможностью поиска и удаления задачи с помощью дополнительных ключей. Но эти детали были бы неуместными и ненужными здесь, я думаю.

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

Отредактировано: изменил код, чтобы правильно бороться с уничтожением*extracted.
Отредактировано: добавлена ​​альтернатива сstd::unique_ptr.
Отредактировано: добавлен второй альтернативныйsehe.

Жить на Колиру

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <iostream>
#include <type_traits>

struct moveonly {
    int x;
    moveonly(int x) noexcept : x(x) {}
    moveonly(moveonly&& o) noexcept : x(o.x) { o = {-1}; }
    moveonly& operator=(moveonly o) noexcept { using std::swap; swap(x, o.x); return *this; }
};

static_assert(not std::is_copy_constructible<moveonly>{}, "moveonly");

namespace bmi = boost::multi_index;
using Table   = bmi::multi_index_container<moveonly,
    bmi::indexed_by<
        bmi::random_access<bmi::tag<struct _ra> >
    > >;

template <typename Container>
void dump(std::ostream& os, Container const& c) { 
    for (auto& r: c) os << r.x << " ";
    os << "\n";
}

moveonly pop_front(Table& table) {
    std::aligned_storage<sizeof(moveonly), alignof(moveonly)>::type buffer;
    moveonly* extracted = reinterpret_cast<moveonly*>(&buffer);

    auto it = table.begin();
    if (it == table.end())
        throw std::logic_error("pop_front");

    if (table.modify(it, [&](moveonly& v) { new (extracted) moveonly{std::move(v)}; })) {
        table.erase(it);
    }

    try {
        moveonly ret = std::move(*extracted);
        extracted->~moveonly();
        return ret;
    } catch(...) {
        extracted->~moveonly();
        throw;
    }
}

int main() {
    Table table;

    table.push_back({1});
    table.push_back({2});
    table.push_back({3});

    dump(std::cout << "table before: ", table);

    std::cout << "Extracted: " << pop_front(table).x << "\n";

    dump(std::cout << "table after: ", table);
}

То же самое, используяstd::unique_ptr для очистки:

Жить на Колиру

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <iostream>
#include <memory>
#include <type_traits>

struct moveonly {
    int x;
    moveonly(int x) noexcept : x(x) {}
    moveonly(moveonly&& o) noexcept : x(o.x) { o = {-1}; }
    moveonly& operator=(moveonly o) noexcept { using std::swap; swap(x, o.x); return *this; }
};

static_assert(not std::is_copy_constructible<moveonly>{}, "moveonly");

namespace bmi = boost::multi_index;
using Table   = bmi::multi_index_container<moveonly,
    bmi::indexed_by<
        bmi::random_access<bmi::tag<struct _ra> >
    > >;

template <typename Container>
void dump(std::ostream& os, Container const& c) { 
    for (auto& r: c) os << r.x << " ";
    os << "\n";
}

moveonly pop_front(Table& table) {
    std::aligned_storage<sizeof(moveonly), alignof(moveonly)>::type buffer;
    moveonly* extracted = reinterpret_cast<moveonly*>(&buffer);

    auto it = table.begin();
    if (it == table.end())
        throw std::logic_error("pop_front");

    if (table.modify(it, [&](moveonly& v) { new (extracted) moveonly{std::move(v)}; })) {
        table.erase(it);
    }

    std::unique_ptr<moveonly,void(*)(moveonly*)> ptr = {
        extracted,
        [](moveonly* p){ p->~moveonly(); }
    };

    return std::move(*extracted);
}

int main() {
    Table table;

    table.push_back({1});
    table.push_back({2});
    table.push_back({3});

    dump(std::cout << "table before: ", table);

    std::cout << "Extracted: " << pop_front(table).x << "\n";

    dump(std::cout << "table after: ", table);
}

Sehe предоставляет еще одну альтернативу, основанную наboost::optional который является самым элегантным из всех:

Жить на Колиру

#include <boost/multi_index_container.hpp>
#include <boost/optional.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <iostream>
#include <memory>
#include <type_traits>

struct moveonly {
    int x;
    moveonly(int x) noexcept : x(x) {}
    moveonly(moveonly&& o) noexcept : x(o.x) { o = {-1}; }
    moveonly& operator=(moveonly o) noexcept { using std::swap; swap(x, o.x); return *this; }
};

static_assert(not std::is_copy_constructible<moveonly>{}, "moveonly");

namespace bmi = boost::multi_index;
using Table   = bmi::multi_index_container<moveonly,
    bmi::indexed_by<
        bmi::random_access<bmi::tag<struct _ra> >
    > >;

template <typename Container>
void dump(std::ostream& os, Container const& c) { 
    for (auto& r: c) os << r.x << " ";
    os << "\n";
}

moveonly pop_front(Table& table) {
    boost::optional<moveonly> extracted;

    auto it = table.begin();
    if (it == table.end())
        throw std::logic_error("pop_front");

    if (table.modify(it, [&](moveonly& v) { extracted = std::move(v); })) {
        table.erase(it);
    }

    return std::move(*extracted);
}

int main() {
    Table table;

    table.push_back({1});
    table.push_back({2});
    table.push_back({3});

    dump(std::cout << "table before: ", table);

    std::cout << "Extracted: " << pop_front(table).x << "\n";

    dump(std::cout << "table after: ", table);
}
 Slava07 сент. 2017 г., 14:52
К сожалению, трудно предсказуемая стоимость перестройки индексов делает изменение элемента копируемым более предпочтительным, чем использование этого решения. Я удивлен, что что-то вродеelement_type&& move_front(); и более общийelement_type &&extract( iterator it ); не был реализован. Есть ли сложности с этим или никто не просил? Этот метод не кажется значительно сложнее, чем простойpop_front() а такжеerase() но я не в курсе внутренних дел.
 Joaquín M López Muñoz07 сент. 2017 г., 15:05
@ Слава с помощьюstd::unique_ptr без специального средства удаления подразумевается, что в процессе выделяется куча, которая, как правило, стоит дороже, чем любой материал на основе стека, который можно использовать в качестве альтернативы.
 Slava07 сент. 2017 г., 15:03
Кстати, почему бы не использоватьstd::unique_ptr<moveonly> и в конце простоreturn std::move( *ptr );, что исключило бы размещение новых осложнений и создание ненужного экземпляра.
 sehe07 сент. 2017 г., 14:12
Ах. Это было проще, чем я себе представлял. Каким-то образом работа с необработанным хранилищем пугает меня больше, чем строго необходимо :)
 sehe07 сент. 2017 г., 18:34
Глядя на разборку, кажется, что с помощьюboost::optional<moveonly> внутренне делает «сложные» вещи с выровненным хранилищем:coliru.stacked-crooked.com/a/b8908ffafeecc228

Ваш ответ на вопрос