C++ Сравните стеки общих указателей

Допустим, у меня есть стек, который содержит общие указатели для int, как показано ниже:

#include <stack>
#include <memory>

using namespace std;

int main()
{
    stack<shared_ptr<int>> s1;
    stack<shared_ptr<int>> s2;

    shared_ptr<int> v1 = make_shared<int>(1);
    shared_ptr<int> v2 = make_shared<int>(1);

    s1.push(v1);
    s2.push(v2);

    bool areEqual = s1 == s2; // This is false
}

Как заставить стеки сравнивать фактические значения, на которые указывает shared_ptr, а не сами указатели?

вы не знаете. доступ к стеку ограничен push и pop. Если вам нужно сравнить равенство, вам нужно будет использовать вектор.

Richard Hodges 19.02.2019 06:40

Насколько stack актуально? Попробуйте bool b = make_shared<int>(1) == make_shared<int>(1);

Sid S 19.02.2019 06:49

Вы пытаетесь сравнить весь стек и убедиться, что все значения, на которые ссылаются указатели, идентичны в обоих стеках? Или вы просто пытаетесь проверить, что вершина каждого стека эквивалентна по стоимости?

selbie 19.02.2019 06:59

Я пытаюсь сравнить весь стек и проверить все значения, на которые ссылаются указатели.

ReeSSult 19.02.2019 07:11
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
4
130
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

std::stack имеет защищенный член c, который является экземпляром базового типа контейнера. Вы можете создать оболочку стека, которая обращается к этой переменной, а затем сравнивать содержимое базовых контейнеров следующим образом:

#include <iostream>
#include <stack>
#include <memory>
#include <algorithm>

using namespace std;

template<class stack_type>
struct stack_wrapper : stack_type
{
    auto begin() const
    {
        return stack_type::c.begin();
    }

    auto end() const
    {
        return stack_type::c.end();
    }
};

template<class stack_type>
const stack_wrapper<stack_type> &wrap(const stack_type &stack)
{
    return static_cast<const stack_wrapper<stack_type> &>(stack);
}

int main() {
    stack<shared_ptr<int>> s1;
    stack<shared_ptr<int>> s2;

    shared_ptr<int> v1 = make_shared<int>(1);
    shared_ptr<int> v2 = make_shared<int>(1);

    s1.push(v1);
    s2.push(v2);

    const auto &s1wrapper = wrap(s1);
    const auto &s2wrapper = wrap(s2);

    const auto is_equal = std::equal(s1wrapper.begin(),
        s1wrapper.end(),
        s2wrapper.begin(),
        s2wrapper.end(),
        [](auto &first, auto &second) {
            return first && second && *first == *second;
        });

    std::cout << is_equal << std::endl;
}

Добавление объявлений в пространство имен std приглашает на насест носачих демонов. Особенно когда они уже определены. Я изначально проголосовал против, но последнее предложение искупает. Просто удалите первое плохое предложение.

StoryTeller - Unslander Monica 19.02.2019 06:57

Я согласен, что это ужасное решение проблемы.

Deedee Megadoodoo 19.02.2019 06:59

Тогда зачем предлагать? Переполнение стека предназначен для хранения знаний стоящий.

StoryTeller - Unslander Monica 19.02.2019 07:02

Снимите пушки, ребята, я исправил свое ужасное решение

Deedee Megadoodoo 19.02.2019 07:10

Вы официально заслужили мой голос. Ваше оригинальное решение заставило меня проголосовать против, но предложение в конце не давало мне покоя.

Sailanarmo 19.02.2019 07:12

возможно, стоит указать, что конструкция оболочки вызывает копирование стека. возможно, было бы лучше, если бы он был назван как-то вроде augmented_stack и использовался в качестве основного контейнера.

Richard Hodges 19.02.2019 07:50

@RichardHodges - копии нет. Все приведения и возвращаемые значения включают только ссылки.

StoryTeller - Unslander Monica 19.02.2019 07:53

@StoryTeller ах да, это хуже, чем я думал

Richard Hodges 19.02.2019 07:55

Мне нравится Ответ @RealFresh. Он точно демонстрирует, насколько на самом деле «инкапсулируется» защищенный доступ. Но приведение ссылки подобъекта базового класса к ссылке подобъекта производного класса и последующее обращение с ней как с таковой может быстро привести к неопределенному поведению.

Однако идея извлечения члена c здрава. Мы можем сделать это без риска UB с помощью простой утилиты:

template<class S>
constexpr decltype(auto) stack_c(S&& s) {
    using base = std::decay_t<S>;
    struct extractor : base {
        using base::c;
    };
    constexpr auto c_ptr = &extractor::c;
    return std::forward<S>(s).*c_ptr;
} 

Из-за того, что выражение &extractor::cработает, мы фактически получаем указатель на член base (специализацию std::stack) с именем c. Цель extractor — сделать имя общедоступным через объявление использования.

Затем мы возвращаем ссылку на него, ценностная категория сохраняется и все. Это замена @RealFresh, предлагающая использовать std::equal:

bool areEqual = std::equal(
    stack_c(s1).begin(), stack_c(s1).end(),
    stack_c(s2).begin(), stack_c(s2).end(),
    [](auto const& p1, auto const& p2) {
        return first && second && (p1 == p2 || *p1 == *p2);
    }
); 

See it live

Очень умно, но ведь это должно быть УБ, не так ли?

Richard Hodges 19.02.2019 07:53

@RichardHodges - Нет. extractor делает имя c доступным. Затем формирование указателя на элемент &extractor::c фактически дает тип C stack<T, C>::*. Это все в связанном стандартном абзаце.

StoryTeller - Unslander Monica 19.02.2019 07:55

Согласованный. Просто показывает - protected действительно означает public и никогда не должен использоваться.

Richard Hodges 19.02.2019 07:58

@RichardHodges - Действительно!

StoryTeller - Unslander Monica 19.02.2019 07:58

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