2015-02-28 3 views
1

У меня есть класс сетки объявлен следующим образом:динамическая инициализация станд :: вектор <unique_ptr <class T>>

Grid.h

#ifndef DATATEST_GRID_H 
#define DATATEST_GRID_H 

#include <memory> 
#include <vector> 
#include "Position.h" 

class Grid 
{ 
public: 
    Grid(int length_x, int length_y); 
    ~Grid(); 

    Position *at(int x, int y); 
    void printGrid(); 

private: 
    int length_x, length_y; 
    std::vector<std::unique_ptr<Position>> grid; 
}; 

#endif 

Его наиболее важной переменной является членом vector<unique_ptr<Position>>, который я используя для имитации двумерного массива, размер которого определяется во время выполнения. Объявление класса для установки выглядит следующим образом:

Position.h

#ifndef DATATEST_POSITION_H 
#define DATATEST_POSITION_H 

#include <memory> 
#include <string> 

class Position { 
public: 
    Position(int x, int y); 
    ~Position(); 

    std::string toString(); 
    int getX() { return x; }; 
    int getY() { return y; }; 

private: 
    int x, y; 
}; 

#endif 

В конструкторе сетки, я хочу, чтобы создать нужное количество позиций и добавить их к vector<unique_ptr<Position>>.

Grid.cpp

#include "Grid.h" 
#include <iostream> 
#include <memory> 
#include <vector> 
#include "Position.h" 

Grid::Grid(int length_x, int length_y) 
    : length_x(length_x), length_y(length_y) 
{ 
    grid.resize(length_x * length_y); 

    for (int x = 0; x < length_x; x++) { 
     for (int y = 0; y < length_y; y++) { 
      /* Option 1 */ 
      std::unique_ptr<Position> temp = std::make_unique<Position>(x, y); 
      grid.push_back(std::move(temp)); 

      /* Option 2 */ 
      // std::unique_ptr<Position> temp = std::make_unique<Position>(x, y); 
      // grid.emplace_back(std::move(temp)); 

      /* Option 3 */ 
      // grid.push_back(std::make_unique<Position>(x, y)); 

      /* Option 4 */ 
      // grid.emplace_back(std::make_unique<Position>(x, y)); 
     } 
    } 
} 

Grid::~Grid() 
{ 
    grid.clear(); 
} 

Position *Grid::at(int x, int y) 
{ 
    if (x < 0 || x >= length_x || y < 0 || y >= length_y) { 
     return nullptr; 
    } 
    else { 
     return grid.at(x * (length_y) + y).get(); 
    } 
} 

void Grid::printGrid() 
{ 
    for (int i = 0; i < grid.size(); i++) { 
     std::cout << grid.at(i)->toString() << std::endl; 
    } 
} 

Я проверяю доступ по телефону Позиция :: ToString для каждого unique_ptr<Position> и печать результата на консоль.

Position.cpp

#include "Position.h" 
#include <string> 

Position::Position(int x, int y) 
    : x(x), y(y) 
{ 
} 

Position::~Position() 
{ 
} 

std::string Position::toString() 
{ 
    return "Position(" + std::to_string(x) + ", " + std::to_string(y) + ")"; 
} 

И, наконец, главная функция:

main.cpp

#include "Grid.h" 
#include "Position.h" 

int main() 
{ 
    Grid g(2, 2); 
    g.printGrid(); 

    return 0; 
} 

Независимо от того, какой путь я заселить vector<unique_ptr<Position>>, я всегда получаю следующее сообщение об ошибке :

First-chance excepti on на 0x0087D8A3 в CombatSim.exe: 0xC0000005: Доступ к считыванию нарушения местоположения 0x00000000. Необработанное исключение в 0x0087D8A3 в файле CombatSim.exe: 0xC0000005: место чтения нарушения доступа 0x00000000.

Насколько я знаю, я мог бы иметь один из четырех задач:
1) Я, придающих unique_ptr на созданный объект Позиции в вектор неправильно
2) Я использую неправильный метод для динамически создавать объекты Position.
3) Все вышеперечисленное.
4) Что-то, о чем я не знаю.

+0

Вам нужно будет показать нам _программу, которую мы можем скомпилировать_ и запустить, чтобы воспроизвести проблему. Ваш [MCVE] (http://stackoverflow.com/help/mcve) будет работать нормально. Тот, который вы отлаживали сегодня. –

ответ

0

Кажется, что изменение размера сетки сначала вставляет length_x * length_y уникальные указатели, которые указывают на 0. Ваш push_back должен быть штраф, но ваши реальные элементы начинаются в позиции length_x * length_y в векторе. Я думаю, удаление линии

grid.resize(length_x * length_y); 

должно решить эту проблему. Может быть, кто-то еще может объяснить, почему это происходит.

+0

Спасибо! Согласно [cplusplus.com] (http://www.cplusplus.com/reference/vector/vector/resize/), когда вызывается изменение размера: «Если n больше текущего размера контейнера, содержимое расширяется путем вставки в конце столько элементов, сколько необходимо для достижения размера n. Если значение val указано, новые элементы инициализируются как копии val, иначе они инициализируются значением. " – PreacherJayne

+0

@ user0815 Было бы желательно сначала зарезервировать место для всех этих элементов length_x * length_y', прежде чем добавлять их в вектор, чтобы избежать повторного перераспределения памяти. – emlai

+0

Да, правильно. Я принял решение «изменить размер» и «зарезервировать», как указано. Таким образом, поведение очевидно. Надеюсь, это помогло. – user0815

2

Использование std::vector::reserve(n) вместо std::vector::resize(n) если вы собираетесь push_back те п элементы впоследствии.

resize будет заполнить вектор с инициализированными объектов, поэтому vector.size() будет п после этого.

reserve просто зарезервирует достаточно места для всех n элемент, но не будет вставлять никаких объектов.

+0

Спасибо! Оказывается, это решило проблему, которую я описал в другом посте. – PreacherJayne

Смежные вопросы