Нужно заменить shared_ptr
на unique_ptr, ибо первый не умеет работать с массивами. А unique_ptr
не дает копировать себя. Что в этом случае делать?
**MatrixShape.hpp**
#ifndef MATRIXSHAPE_HPP_INCLUDED
#define MATRIXSHAPE_HPP_INCLUDED
#include <memory>
#include "Shape.hpp"
class MatrixShape
{
public:
MatrixShape(const std::shared_ptr<Shape> &);
MatrixShape(const MatrixShape &);
MatrixShape & operator=(const MatrixShape &);
// HERE std::unique_ptr <std::shared_ptr<Shape>[]>::pointer operator[](const size_t &index) const; // HERE
void addShape(const std::shared_ptr<Shape> &);
void print() const;
private:
std::unique_ptr <std::shared_ptr<Shape>[]> matrix_;
size_t rows_, columns_;
bool checkOverlap(const std::shared_ptr<Shape> &, const std::shared_ptr<Shape> &) const;
};
#endif
#include <iostream>
#include <iomanip>
#include <stdexcept>
#include <cmath>
#include "MatrixShape.hpp"
MatrixShape::MatrixShape(const std::shared_ptr<Shape> &shape):
matrix_(new std::shared_ptr<Shape>[1]),
rows_(1),
columns_(1)
{
if (shape == nullptr)
{
throw std::invalid_argument("invalid pointer");
}
matrix_[0] = shape;
}
MatrixShape::MatrixShape(const MatrixShape &matrix_shape):
rows_(matrix_shape.rows_),
columns_(matrix_shape.columns_)
{
std::unique_ptr <std::shared_ptr<Shape>[]> matrix_copy(new std::shared_ptr<Shape>[rows_ * columns_]);
for (size_t i = 0; i < (rows_ * columns_); i ++)
{
matrix_copy[i] = matrix_shape.matrix_[i];
}
matrix_.swap(matrix_copy);
}
MatrixShape & MatrixShape::operator=(const MatrixShape &matrix_shape)
{
if (this != &matrix_shape)
{
rows_ = matrix_shape.rows_;
columns_ = matrix_shape.columns_;
std::unique_ptr <std::shared_ptr<Shape>[]> matrix_copy(new std::shared_ptr<Shape>[rows_ * columns_]);
for (size_t i = 0; i < (rows_ * columns_); i ++)
{
matrix_copy[i] = matrix_shape.matrix_[i];
}
matrix_.swap(matrix_copy);
}
return *this;
}
std::unique_ptr <std::shared_ptr<Shape>[]>::pointer MatrixShape::operator[](const size_t &index) const
{
if (index > rows_)
{
throw std::invalid_argument("index out of range");
}
return matrix_.get() + index * columns_;
}
void MatrixShape::addShape(const std::shared_ptr<Shape> &shape)
{
if (shape == nullptr)
{
throw std::invalid_argument("invalid pointer");
}
size_t i = rows_ * columns_;
size_t desired_row = 1;
while (i > 0)
{
i --;
if (checkOverlap(matrix_[i], shape))
{
desired_row = i / columns_ + 2;
}
}
size_t rows_temp = rows_;
size_t columns_temp = columns_;
size_t free_columns = 0;
if (desired_row > rows_)
{
rows_temp ++;
free_columns = columns_;
}
else
{
size_t j = (desired_row - 1) * columns_;
while (j < (desired_row * columns_))
{
if (matrix_[j] == nullptr)
{
free_columns ++;
}
j ++;
}
if (free_columns == 0)
{
columns_temp ++;
free_columns = 1;
}
}
std::unique_ptr <std::shared_ptr<Shape>[]> matrix_temp(new std::shared_ptr<Shape>[rows_temp * columns_temp]);
for (size_t i = 0; i < rows_temp; i ++)
{
for (size_t j = 0; j < columns_temp; j ++)
{
if (i >= rows_ || j >= columns_)
{
matrix_temp[i * columns_temp + j] = nullptr;
continue;
}
matrix_temp[i * columns_temp + j] = matrix_[i * columns_ + j];
}
}
matrix_temp[desired_row * columns_temp - free_columns] = shape;
matrix_.swap(matrix_temp);
rows_ = rows_temp;
columns_ = columns_temp;
}
bool MatrixShape::checkOverlap(const std::shared_ptr<Shape> &shape_1, const std::shared_ptr<Shape> &shape_2) const
{
if (shape_1 == nullptr || shape_2 == nullptr)
{
return false;
}
rectangle_t shape_1_frame_rect = shape_1 -> getFrameRect();
rectangle_t shape_2_frame_rect = shape_2 -> getFrameRect();
return ((fabs(shape_1_frame_rect.pos.x - shape_2_frame_rect.pos.x)
< ((shape_1_frame_rect.width / 2) + (shape_2_frame_rect.width / 2)))
&& ((fabs(shape_1_frame_rect.pos.y - shape_2_frame_rect.pos.y)
< ((shape_1_frame_rect.height / 2) + (shape_2_frame_rect.height / 2)))));
}
void MatrixShape::print() const
{
for (size_t i = 0; i < rows_; i ++)
{
for (size_t j = 0; j < columns_; j ++)
{
if (matrix_[i * columns_ + j] != nullptr)
{
std::cout << std::setw(16) << std::left << matrix_[i * columns_ + j] -> getName();
}
}
std::cout << "\n";
}
}
Не надо ничего заменять.
Хоть std::shared_ptr
и не поддерживает массивы в явном виде, мы можем обмануть его, передав указатель на начало массива так, будто это указатель на единственный элемент.
Ведь как работают умные указатели в C++? Они принимают указатель, над которым нужно установить владение, и deleter — функциональный объект, знающий, как корректно освободить данные по этому указателю.
Так как указатель на массив тождественен указателю на первый элемент массива (то есть эти два понятия взаимозаменяемые), то единственное, что нам остаётся — передать умному указателю deleter, работающий с массивами. Кстати, если вы выделяете массив оператором new[]
, то нам подойдёт стандартный std::default_delete<T[]>
.
Для удобства использования обернём создание массива в шаблонный метод:
#include <memory>
template<typename T>
std::shared_ptr<T> allocateArray(size_t n)
{
return std::shared_ptr<T>(new T[n], std::default_delete<T[]>());
}
У данного способа есть один недостаток — вам придётся где-то хранить размер массива.
Как обработать исключение, которое возникает при попытке инициализировать значение за пределами массива, или при чтении из-за его пределовПробовал...
Имеется небольшой класс для создания массива обернутого в shared_ptr, при запуске возникает ошибка : "Невозможно преобразовать int* в int", не могу...
Пытаюсь изменить значение текстового поля из другого потока, но почему-то не работает( Имеется класс MyThread:
Простой код с использованием MPIПри сборке в релиз отладка останавливается в указанном месте на ветке else