Аномалии в кастомном классе строки

67
09 мая 2021, 08:10

Так вот, я начал писать класс для реализации строки C++, хотя использую я методики из C, впрочем сейчас это неважно. Как и обычный класс string из STL основная задача данной приблуды - динамическое выделение памяти под строку.

Я начал писать это чудо, но уже на стадии реализации конструктора класса наткнулся на некую аномалию, она возникает не всегда, но это не меняет ситуацию. Иногда когда я преобразую мой блок для хранения данных в const char* с помощью стандартного type-cast я получаю некую аномалию в конце строки. Стоит подметить что я заметил её когда выводил данные с помощью <iostream> библиотеки.

Мой блок для хранения данных типа uint8_t* или unsigned char*. Впрочем мне понятно как решить данную проблему, нужно просто записать символ окончания строки \0 на конечный адрес блока. Но всё же мне интересно, это обязательно делать, или я что-то сделал не так и теперь из-за этого страдаю?

class string {
private:
    uint8_t* m_data = 0;
    size_t m_length = 0;
public:
    string();
    string(char _var);
    string(char* _var);
    string(const char* _var);
    string(const string& _var);
    const char* to_str() const;
    size_t length() const;
    ~string();
};
string::string() {
    m_data = (uint8_t*)malloc(0);
}
string::string(char _var) {
    m_length++;
    m_data = (uint8_t*)malloc(m_length);
    memcpy_s(m_data, m_length, (void*)_var, m_length);
}
string::string(char *_var) {
    m_length = strlen(_var);
    m_data = (uint8_t*)malloc(m_length);
    memcpy_s(m_data, m_length, (uint8_t*)_var, m_length);
}
string::string(const char* _var) {
    m_length = strlen(_var);
    m_data = (uint8_t*)malloc(m_length);
    memcpy_s(m_data, m_length, (uint8_t*)_var, m_length);
}
string::string(const string& _var) {
    m_length = _var.length();
    m_data = (uint8_t*)malloc(m_length);
    memcpy_s(m_data, m_length, (uint8_t*)_var.to_str(), m_length);
}
const char* string::to_str() const {
    return (const char*)m_data;
}
size_t string::length() const {
    return m_length;
}
string::~string() {
    free(m_data);
}

Данных на этот счёт в интернете я на удивление не нашёл, хотя возможно я просто не правильно задал вопрос.

Answer 1

В первом конструкторе string(char) вы выделяете память под ровно один символ (кстати m_length++ плохая идея, лучше m_length = 1).

Во втором конструкторе string(char*) вы измеряете размер строки при помощи функции strlen, которая принимает «строку в стиле Си» и возвращает размер с учетом терминального нуля. ASCII строка из одного символа всегда будет иметь размер 2.

string('a').length() == 1;
string("a").length() == 2;

Но эти все конструкторы создают нормальную (в широком понимании) копию строки во всех случаях. Ошибка находится в функции to_str(), которая возвращает указатель на константный char, что стандартной библиотекой воспринимается как строка в стиле Си и, соответственно, должна иметь терминальный ноль. Что имеет смысл, ведь указатель на память не несёт информации о том, сколько этой памяти доступно.

Здесь нужно сделать выбор: либо хранить всегда терминальный ноль в строке, либо всегда его убирать. Если его не хранить, то единственная выгода - экономия одного байта. А при конвертировании в строку в стиле Си придётся выделять память, дописывать ноль, а потом ещё и удалять её. А если хранить, то нужно лишь в нескольких местах обработать этот случай.

Есть ещё третий вариант – убрать из интерфейса конвертацию в строку в стиле Си, что сильно сузит область применения этой библиотеки.

READ ALSO
не работает Progress bar в firefox

не работает Progress bar в firefox

Всем привет! Появилась такая проблемаУ меня не работает progress bar в firefox

130
Как выровнять текст и иконку по центру?

Как выровнять текст и иконку по центру?

Как выровнять текст и иконку по центру,чтобы они были на одном уровне ? На данный момент текст находится у нижней части иконки

84
Как вывести данные в порядке обратном от того, в котором они лежат в БД?

Как вывести данные в порядке обратном от того, в котором они лежат в БД?

У меня есть поле поле pipe_n, в котором данные лежат так:

100