#c #c 14
#c #c 14
Вопрос:
Я попытался объявить пустой указатель на указатель, присвоить ему указатель на выделенную во время построения память и повторить его, выполнив назначение снова, но я что-то упускаю. Также мне интересно, возможно ли это сделать с std::array
помощью . Прикрепление кода:
// Cell.h
class Cell {
char contents;
bool is_free;
};
// Memory.h
#include "Cell.h"
#include <cstddef>
class Memory {
public:
Memory(std::size_t nlines, std::size_t ncols);
private:
Cell **cells;
};
// Memory.cpp
#include "Memory.h"
Memory::Memory(std::size_t nlines, std::size_t ncols):
cells(new Cell[nlines]) // Cannot initialize a member subobject of type 'Cell **' with an rvalue of type 'Cell *'
{
for (std::size_t i = 0; i < nlines; i)
cells[i] = new Cell[ncols];
}
Кроме того, мне нужно, чтобы мой массив содержал ячейки со значениями char contents = '.', bool is_free = true
после его инициализации. Каков наилучший способ сделать это?
UPD: я подумал о создании 2D псевдомассива с использованием одного указателя (не указателя на указатель) и доступа к ячейке с i*ncols j
помощью .
Комментарии:
1. Сообщение об ошибке для инициализации ячеек здесь довольно информативно. Вы пытаетесь присвоить
Cell[nlines]
(т.Е. Одномерный массив) чему-то типаCells **
(2D-массив). Вам нужно изменить эту строку наcells(new Cell*[nlines])
Ответ №1:
Также мне любопытно, возможно ли это сделать с помощью std::array
Вы не можете, размер an std::array
указан в качестве параметра шаблона, и ваш массив имеет динамический размер.
Вместо того, чтобы иметь дело с необработанными указателями, вам следует std::vector
искать массивы с динамическим размером:
std::vector<std::vector<Cell>> cells{ncols, std::vector{nlines, Cell{}}};
Ключевым преимуществом является то, что вам не нужно вручную выделять память и управлять ею.
UPD: я подумал о создании 2D псевдомассива с использованием одного указателя (не указателя на указатель) и доступа к ячейке с помощью i* ncols j .
Это гораздо лучшая идея, хранение ваших данных в одном плоском векторе уменьшает фрагментацию.
std::vector<Cell> cells(nlines*ncols, Cell{});
Чтобы упростить доступ, вы можете обернуть этот вектор 1D в класс, который предоставляет a operator()(std::size_t row, std::size_t col)
, который выполняет преобразование индексов (row, col) в местоположение в массиве 1d.
Комментарии:
1. Спасибо. Также я понял, что мне не нужно перебирать массив и вручную назначать каждую ячейку. Итак
new
, в c заполняет память элементами со значениями по умолчанию?2. И есть ли какая-либо разница между инициализацией значений по умолчанию в объявлении класса и его конструкторе?
3. Ваш вопрос мне неясен, фрагмент кода поможет. Если вы имеете в виду, есть ли разница между 1)
Cell cell1;
и 2)Cell cell2 = Cell{};
, нет, они дают тот же результат для вашего класса.4.
struct Cell { char contents = '.'; bool is_free = true };
иstruct Cell { char contents; bool is_free; Cell(char contents = '.', bool is_free = true) :contents(contents), is_free(is_free) { } };
. У меня такое чувство, что они взаимны, но я слышал, что агрегаты не могут иметь инициализаторов, поэтому мне любопытно, есть ли еще какие-либо различия.5. Ах, я неправильно понял, в этом случае первое предпочтительнее IMO, но это вопрос стиля.
Ответ №2:
Вам нужно написать
Memory::Memory(std::size_t nlines, std::size_t ncols)
:cells(new *Cell[nlines])
{
...
}
(Обратите внимание на Cell *
вместо Cell
).
std::array
это только фиксированный размер массива во время компиляции, поэтому он не подходит для ваших целей.
Я бы согласился с вашим редактированием. Не используйте массив указателей для матриц, используйте метод плоского массива с индексацией i*ncols j
. С этим первым сложнее работать и имеет более высокие накладные расходы (из-за большого количества new
вызовов).
Если вы беспокоитесь о накладных расходах на умножение, вы можете создать справочную таблицу для i*ncols
. Но я сомневаюсь, что оно того стоит.