Conversation
af493f6 to
b790932
Compare
3ddd597 to
93e34fe
Compare
| std::size_t rows = 3; | ||
| std::size_t cols = 4; |
There was a problem hiding this comment.
Не критично, но лучше добавить const. Здесь и в других похожих местах.
There was a problem hiding this comment.
Я специально не добавляла const, чтобы подчеркнуть, что для таких массивов длина не обязана быть константой.
| JaggedBuffer(std::size_t row_count, const std::size_t * col_sizes); | ||
|
|
||
| // Освобождает всю память | ||
| ~JaggedBuffer(); | ||
|
|
||
| // Записывает сегмент по индексу | ||
| void set_segment(std::size_t index, const int * segment); |
There was a problem hiding this comment.
JaggedBuffer(std::size_t row_count, const std::size_t * col_sizes)
Сильно сбивает с толку такая сигнатура и наименование. Сразу возникает пара вопросов. Какие столбцы? И сколько их? И только потом понимаешь, что сначала идет количество строк, а потом их длины.
Кроме того традиционно принято сначала передавать массив, а потом его длину:
JaggedBuffer(const std::size_t * segment_sizes, std::size_t segment_count)
void set_segment(std::size_t index, const int * segment)
Это некорректный дизайн интерфейса. Вызывающая сторона где-то независимо от JaggedBuffer должна хранить длину каждой строки и как-то учитывать это при каждом вызове. Недружелюбный и очень ломкий интерфейс. Легко передатьsegmentне той длины.
Предлагаю изменить задачу. Суть:
Данные передаются по каналу связи с негарантированной доставкой (например, используетс протокол UDP). Имеется библиотека написанная на Си, которая обеспечивает гарантированную доставку данных. Библиотека позволяет получить данные по частям (сегментами):
// Дескриптор канала данных.
typedef void* recv_desc_t;
// Функция инициализирует получение данных. Параметры:
// [in] sgm_size - максимальный размер сегмента,
// [out] pdesc - дескриптор канала данных.
// Функция инициализирует дескриптор и возвращает 0 в случае успеха,
// отрицательный код ошибки в противном случае. Код ошибки err_no_memory
// означает, что не удалось выделить память для дескриптора.
int init_recv(size_t sgm_size, recv_desc_t* pdesc);
// Функция завершает получение данных и закрывает дескриптор канала
// данных. Параметры:
// [in/out] pdesc - валидный дескриптор канала данных.
void close_recv(recv_desc_t* pdesc);
// Функция возвращает ожидаемое количество сегментов,
// 0 означает, что все сегменты были получены. Параметры:
// [in] desc - валидный дескриптор канала данных.
size_t sgm_left(recv_desc_t desc);
// Функция возвращает максимальный размер сегмента для указанного
// канала данных. Параметры:
// [in] desc - валидный дескриптор канала данных.
size_t max_sgm_size(recv_desc_t desc);
// Функция возвращает сегмент данных. Параметры:
// [in] desc - валидный дескриптор канала данных,
// [out] idx - индекс сегмента,
// [out] buf - буффер для сохранения сегмента,
// [in/out] size - размер буффера на входе и реальный размер
// сегмента данных на выходе.
// Функция возвращает 0 в случае успеха и отрицательный код ошибки
// в противном случае. Код ошибки err_wait_for_data означает, что
// нужно попробовать вызвать функцию позже. Код ошибки
// err_insufficient_buffer сигнализирует, что размер переданного
// буффера недостаточен, а в size возвращается ожидаемый размер.
int recv_sgm(recv_desc_t desc, size_t* idx, void* buf, size_t* size);Необходимо реализовать класс враппер для Си интерфейса:
template <class T = std::uint8_t>
class JaggedBuffer {
public:
// Конструктор инициализирует канал данных и буффер
// для хранения сегментов. Выбрасывает std::bad_alloc()
// при нехватки памяти.
explicit JaggedBuffer(std::size_t max_segment_size);
~JaggedBuffer();
// Метод получает очередной сегмент данных и сохраняет
// его во внутренний буффер. Возвращает общее количество
// полученных сегментов и обшее количество сегментов.
std::pair<std::size_t, std::size_t> receive_segment();
// Метод компанует сегменты и возвращает собранные во
// едино данные. Выбрасывает std::runtime_error, если
// были получены не все сегменты.
std::vector<T> compose_segments() const;
private:
// Дескриптор канала данных
recv_desc_t m_channel = nullptr;
// Массив сегментов
T ** m_segments = nullptr;
// Длины сегментов
std::size_t * m_sizes;
// Количество сегментов
std::size_t m_count = 0;
};P.S. Напишу сишную либу и эталонный вариант JaggedBuffer, если предложение будет принято.
There was a problem hiding this comment.
Предложение принято. Реализовывай=)
cpp/cpp_chapter_0156/text.md
Outdated
| for (std::size_t i = 0; i < rows; ++i) | ||
| data[i] = nullptr; |
There was a problem hiding this comment.
Лучше использовать алгоритм:
std::fill(data, data + rows, nullptr);|
|
||
| С точки зрения компилятора разницы между этими вариантами записи нет. Потому что при передаче сишного массива в функцию происходит [низведение массива:](/courses/cpp/chapters/cpp_chapter_0132/#block-array-to-pointer-decay) он автоматически приводится к указателю на нулевой элемент. Зато с точки зрения разработчика запись `char* argv[]` более «говорящая»: сразу понятно, что `argv` — это массив указателей на символы `char`. | ||
|
|
||
| Итак, аргументы попадают в `main()` в качестве сишных строк. Чтобы получить из них числа, есть функции: |
There was a problem hiding this comment.
Есть более эффективные функции преобразования строки в число std::from_chars():
https://en.cppreference.com/w/cpp/utility/from_chars.html
Предлагаю использовать их. Не настаиваю, на твоё усмотрение.
There was a problem hiding this comment.
Ими гораздо сложнее пользоваться. А глава и так не простая. Предлагаю оставить как есть.
|
|
||
| ---------- | ||
|
|
||
| ## Резюме |
There was a problem hiding this comment.
Ещё двойные указатели нужны при взаимодействии с Си-шными интерфейсами.
НЕ ГОТОВА, СМОТРЕТЬ РАНО