Так вот, я начал писать класс для реализации строки 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);
}
Данных на этот счёт в интернете я на удивление не нашёл, хотя возможно я просто не правильно задал вопрос.
В первом конструкторе string(char)
вы выделяете память под ровно один символ (кстати m_length++
плохая идея, лучше m_length = 1
).
Во втором конструкторе string(char*)
вы измеряете размер строки при помощи функции strlen
, которая принимает «строку в стиле Си» и возвращает размер с учетом терминального нуля. ASCII строка из одного символа всегда будет иметь размер 2.
string('a').length() == 1;
string("a").length() == 2;
Но эти все конструкторы создают нормальную (в широком понимании) копию строки во всех случаях. Ошибка находится в функции to_str()
, которая возвращает указатель на константный char, что стандартной библиотекой воспринимается как строка в стиле Си и, соответственно, должна иметь терминальный ноль. Что имеет смысл, ведь указатель на память не несёт информации о том, сколько этой памяти доступно.
Здесь нужно сделать выбор: либо хранить всегда терминальный ноль в строке, либо всегда его убирать. Если его не хранить, то единственная выгода - экономия одного байта. А при конвертировании в строку в стиле Си придётся выделять память, дописывать ноль, а потом ещё и удалять её. А если хранить, то нужно лишь в нескольких местах обработать этот случай.
Есть ещё третий вариант – убрать из интерфейса конвертацию в строку в стиле Си, что сильно сузит область применения этой библиотеки.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Всем привет! Появилась такая проблемаУ меня не работает progress bar в firefox
Как выровнять текст и иконку по центру,чтобы они были на одном уровне ? На данный момент текст находится у нижней части иконки
У меня есть поле поле pipe_n, в котором данные лежат так: