2015-09-27 4 views
2

Мне нужно поставить std::vector в std::stack.Как инициализировать std-стек с помощью std-вектора?

Вот мой метод до сих пор (я строй карточной игры):

void CardStack::initializeCardStack(std::vector<Card> & p_cardVector) { 
    m_cardStack = std::stack<Card>(); 
    //code that should initialize m_cardStack with p_cardVector 
} 

Примечание: Я не могу изменить сигнатуру методы, потому что это налагается учителем ...

Do Я должен перебирать весь вектор? Каков наиболее эффективный способ сделать это? documentation.

Я попытался ответить Йенсу, но это не сработало.

+1

Либо пройти вектор по константной-ссылке, так как он не модифицируется, или по значению и переместить содержимое в стек. Последняя версия позволяет компилятору генерировать более эффективный код в тех же случаях. – Jens

+0

'std :: stack <....>' из чего? По умолчанию 'stack' использует в качестве основного контейнера' deque', а не 'vector'. –

+0

См. Мое редактирование. Я добавил больше контекста. – AlexB

ответ

3

std::stack не имеет конструктор, который принимает итераторы, так что вы могли бы построить временный deque и инициализировать стек с этим:

void ClassName::initializeStack(std::vector<AnotherClass> const& v) { 
    m_stackAttribute = std::stack<AnotherClass>(std::stack<AnotherClass>::container_type(v.begin(), v.end())); 
} 

Однако, это копирует каждый элемент в контейнер. Для достижения максимальной эффективности, вы должны также использовать Move-семантику для устранения копий

void ClassName::initializeStack(std::vector<AnotherClass>&& v) { 
    std::stack<AnotherClass>::container_type tmp(std::make_move_iterator(v.begin()), std::make_move_iterator(v.end())); 
    m_stackAttribute = std::stack<AnotherClass>(std::move(tmp)); 
} 
+0

Этот код не работает для меня. Я смотрю документацию, и я нашел эту подпись метода move-initialize (2) \t Явный стек (container_type && ctnr = container_type()); – AlexB

+0

@AlexB Исправлено. Аргументы шаблона для стеков отсутствовали. Рабочий код по адресу http://cpp.sh/8l7kk. – Jens

+0

Он компилируется, но размер равен 0. Стек не заполняется векторными значениями – AlexB

0

Самый эффективный способ вообще не использовать std::stack и просто использовать std::vector или даже лучше для этого использовать std::deque.

Я видел и написал много кода C++ (много), но я пока найти применение для stack вещи (любого содержательного использования, то есть). Было бы иначе, если базовый контейнер можно было бы изменить или определить тип контейнера во время выполнения, но это не так.

Чтобы скопировать элементы из std::vector в std::deque вы можете просто использовать

std::deque<T> stack(vec.begin(), vec.end()); 

Это позволит реализация использовать наиболее эффективный способ для копирования элементов.

Чтобы явным образом ответить на ваш вопрос: да, единственный способ поместить элементы в стек - это вставить их в цикл. Это неэффективно, но интерфейс стека не определяет ничего другого. Тем не менее, кто написал код, принимающий параметр std::stack, должен быть запущен (если он/она не обещает, что это никогда не повторится), и его код вернется к чему-то более разумному: вы получите то же (отсутствие) «гибкость», но лучший интерфейс.

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

+2

Я думаю, что «std :: stack» и 'std :: deque' имеют одно преимущество перед использованием базового контейнера. Они выражают намерение использовать стек, и когда я смотрю на код, я сразу вижу, что используется стек. С помощью 'vector', я должен выяснить, как он используется, или посмотреть, надеюсь, существующие комментарии. Поэтому я бы сказал, что помимо других вопросов они имеют очень полезный смысл. – Jens

+0

@Jens: 'std :: deque' - это контейнер, а не адаптер, и это очень полезно. 'std :: stack' с другой стороны просто удаляет методы, не предоставляя ничего. Предоставление минимальных интерфейсов иногда полезно, но только если вы можете скрыть/защитить реального провайдера; это работа интерфейсов (но 'std :: stack' не является интерфейсом, потому что базовый контейнер содержится, а не ссылочный, и его тип должен быть известен временем компиляции, удаляя любую гибкость, которую добавит интерфейс). – 6502

+0

Стек и очередь могут не предоставлять функциональность, но они выражают намерение. Я считаю это полезным при чтении кода. Это также четко выражает контракт функций на уровне типа. Но я согласен с тем, что было бы лучше иметь стек стека или очередь в STL, а deque должен быть моделью для очереди. Или, может быть, обертку с тиснением, которая выражает это намерение. Я просто не сказал бы, что это совершенно бесполезно. – Jens