LINUX.ORG.RU

ввод/вывод вектора указателей

 


0

2

почему в

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

using namespace std;

int main(int argc, char *argv[])
{
  vector<int> queue;
  vector<int*> pqueue;

  int n;
  cin >> n;
  
  while (cin.good()) {
    queue.push_back(n);
    pqueue.push_back(&queue.back());
    cin >> n;
  }

  copy(queue.begin(), queue.end(), ostream_iterator<int>(cout, " "));
  cout << endl;

  for (vector<int*>::const_iterator it = pqueue.begin(); it < pqueue.end(); ++it)
    cout << **it << " ";
  cout << endl;

  return 0;
}
при выводе вектора указателей первое число не совпадает с вектором целых?
$ echo 1 2 3 4 q |./lab7
1 2 3 4 
146047008 2 3 4
как сделать правильно? Нужно именно в цикле вводить число, добавлять его значение в один вектор, указатель в другой

Может быть std::vector queue выделил память в другом месте.
Тогда элемент pqueue ссылается на невалидную область памяти.

nerdogeek
()

Вектор сам выделяет память под объекты, но её может не хватить - в этом случае он выделит более крупный кусок, скопирует в него данные, а старый затрёт.

Соответственно после каждого push_back указатель на элемент вектора может стать невалидным.

Нужно именно в цикле вводить число, добавлять его значение в один вектор, указатель в другой

Насколько я помню, ни один контейнер STL не гарантирует, что после добавления значения ранее взятые указатели на элементы контейнера остаются валидными. Можно сжульничать: узнать максимальное допустимое количество чисел и сделать queue.reserve(maxcount). В реальном коде так никогда не делайте.

quiet_readonly ★★★★
()
Ответ на: комментарий от frozenix

никто, мне тоже вообщем-то показалось странным что остальные правильно вывелись

sergeek
() автор топика

vector гарантирует непрерывность своих элементов в памяти, но при этом он динамический, то есть может перемещать их во время мутаций (push_back). Можешь сначала заполнить queue, потом взять queue.data() и из него заполнить pqueue, но это значит, что больше queue менять нельзя. Либо сделать свои указатели в куче / арене (это самодельная куча в куче или на стеке с upper bound):

  vector<unique_ptr<int> > pqueue;

      pqueue.push_back(unique_ptr<int> { new int(n) });
quasimoto ★★★★
()
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

using namespace std;

int main(int argc, char *argv[])
{
  vector<int> queue;
  vector<int*> pqueue;

  int n;
  cin >> n;
  
  while (cin.good()) {
    queue.push_back(n);
    cin >> n;
  }

  for (auto &x : queue) {
      pqueue.push_back(&x);
  }

  copy(queue.begin(), queue.end(), ostream_iterator<int>(cout, " "));
  cout << endl;

  for (vector<int*>::const_iterator it = pqueue.begin(); it < pqueue.end(); ++it)
    cout << **it << " ";
  cout << endl;
  return 0;
}

Но если ты сделаешь какую-нибудь модифицирующую вектор операцию(не элементы, а сам вектор), то все пропало - в pqueue будут невалидные указатели... Если не собирается из-за auto и такого for'а, значит компилятор компилит по старому стандарту.

Ты какую задачу решить хочешь? Может объекты создавать в куче?

anonymous
()
Ответ на: комментарий от quiet_readonly

Насколько я помню, ни один контейнер STL не гарантирует, что после добавления значения ранее взятые указатели на элементы контейнера остаются валидными.

Неправильно. set и list гарантируют.

Можно сжульничать: узнать максимальное допустимое количество чисел и сделать queue.reserve(maxcount). В реальном коде так никогда не делайте.

Это не жульничанье. И это нормально, если гарантируется что queue не будет изменяться. const vector, например.

Тут проще будет просто заполнить pqueue после того как queue заполнен.

slovazap ★★★★★
()
Ответ на: комментарий от anonymous

так не подойдет, ага. Мне нужно в том while цикле по мере добавления чисел путем ввода тут же их сортировать. Собственно задача следующая:

Разработать программу формирования очереди, содержащей целые числа, и упорядочивания по возрастанию элементов в этой оче реди. В процессе упорядочивания элементы очереди перемещаться не должны.

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

sergeek
() автор топика
Ответ на: комментарий от sergeek

условие стремное, честно говоря. Если эту очередь сортировать то она уже никакая не очередь. Не совсем ясно нужно ли сделать возможным выводить значения очереди, если нет то можно и после цикла отсортировать, как у анонимуса

sergeek
() автор топика
Ответ на: комментарий от sergeek

условие стремное, честно говоря.

Да нормальное, вроде. Представь, что в очереди большие объекты и нужно сохранить их порядок, но при этом получать и сортированный вариант периодически - нужно завести (более лёгкий) вектор указателей на эти большие объекты и его сортировать кастомной сортировкой. Если взять твой код, заменить две строчки как я выше писал и добавить

        sort(pqueue.begin(), pqueue.end(),
             [] (const unique_ptr<int> &x, const unique_ptr<int> &y) -> bool
             {
                 return *x < *y;
             });

то это оно и будет. Можно заменить unique_ptr на обычный сырой указатель, делать delete по pqueue в конце, или умещать pqueue на стеке.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

нужно завести (более лёгкий) вектор указателей на эти большие объекты

Хотя с vector под queue тут и получается фейл - тогда уж брать std::queue под оригинальную очередь и std::map/std::priority_queue под сортированную и параллельно их заполнять. Или делать как anonymous, потом тот же sort на pqueue и больше не трогать queue.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Представь...

да, почему-то такое не пришло в голову :) Решение то что надо, только боюсь у меня не примут его на с++11, а в кучи и стеки я не умею.

sergeek
() автор топика
Ответ на: комментарий от sergeek

Я думаю нужно просто взять ordered dynamic iterable контейнер для очереди у которого &queue.front() будет сохраняться и sorted ordered dynamic iterable контейнер указателей с кастомной функцией сортировки - сортировка будет получаться автоматом. То есть, видимо, list и map - что-то такое:

// C++ 98

#include <list>
#include <map>
#include <iterator>
#include <iostream>

using namespace std;

typedef int Object;

typedef list<Object> Queue;

struct SortedQueueComparator {
    bool operator()(const Object *x, const Object *y) {
        return *x < *y || x < y;
    }
};

typedef map<Object*, Object, SortedQueueComparator> SortedQueue;
typedef pair<Object*, Object> Pair;

int main()
{
    Queue q;
    SortedQueue sq;

    int n;
    cin >> n;
    while (cin.good()) {
        q.push_front(n);
        sq.insert(Pair(&q.front(), q.front()));
        cin >> n;
    }

    copy(q.begin(), q.end(), ostream_iterator<Object>(cout, " "));
    cout << endl;

    for (SortedQueue::const_iterator it = sq.begin(); it != sq.end(); ++it)
        cout << it->second << " ";
    cout << endl;
}
quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Спасибо! Очень вам признателен. Буду разбираться. Как тяжело все-таки в этих плюсах ориентироваться. Не завидую вам. Впрочем, вам-то, может быть, и ок, вы все или многое уже знаете, а вот ньюфагам, наверное, очень плохо.

sergeek
() автор топика

А так уже нельзя?

printf ("%p", pointer);

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.