Проблема с вашим конструктором String(const char* chars)
заключается в следующем утверждении:
str = new char[len - 1];
Вы выделяете меньше памяти, тогда вам нужно, поэтому ваш for
l oop выход за пределы выделенной памяти. Вам нужно выделить как минимум len
количество символов, а не len - 1
количество символов:
str = new char[len];
Если вы намерены str
завершить нулем, вам нужно вместо этого выделите len + 1
количество символов, а затем вставьте нулевой терминатор после завершения l oop:
str = new char[len + 1];
for(int j = 0; j < len; j++){
str[j] = chars[j];
}
str[len] = '\0';
Вы делаете аналогичную ошибку в вашем методе toChars()
. Вы не завершаете вывод на нуль, что требуется для operator<<
, которому вы передаете память впоследствии:
const char* toChars() const {
char* temp = new char[len + 1];
for(int c = 0; c < len; ++c){
temp[c] = str[c];
}
temp[len] = '\0';
return temp;
}
Обратите внимание, что я удалил noexcept
на toChars()
. Это потому, что new[]
не является noexcept
, он может выдать исключение std::bad_alloc
, если не может выделить память, которую вы не перехватываете. noexcept
означает, что метод не throw
вообще исключений, но здесь это не так.
Есть и другие проблемы с вашим кодом, также:
-
Ваш деструктор теряет память, если len
равен 0, ie, если вызывается ваш конструктор по умолчанию или ваш конструктор Converting вызывается с нулевой / пустой строкой. Если вы звоните new[]
, вам нужно позвонить delete[]
, независимо от используемого len
.
Ваш конструктор Copy не инициализирует str
или len
, если String
копируется пусто.
В main()
вы не delete[]
сохраняете память, которую возвращает toChars()
.
необязательно для данной конкретной ситуации, но в целом вам не хватает оператора копирования. И, поскольку вы явно используете C ++ 11 или более позднюю версию, вы также должны добавить конструктор Move и оператор Move Assignment. См. Правило 3/5/0 .
Попробуйте это вместо этого (без дополнительных библиотечных функций, добавленных для запроса):
#include <iostream>
using namespace std;
class String {
public:
char* str = nullptr;
unsigned int len = 0;
String() = default;
String(const char* chars) {
if (chars) {
unsigned int i = 0;
while (chars[i]) {
++i;
}
len = i;
str = new char[len];
for(int j = 0; j < len; ++j) {
str[j] = chars[j];
}
}
}
String(const String& s) {
if (!s.isEmpty()) {
len = s.len;
str = new char[len];
for(int i = 0; i < len; ++i){
str[i] = s.str[i];
}
}
}
~String() noexcept {
delete[] str;
}
String& operator=(const String &s) {
if (&s != this) {
String tmp(s);
char *tmpstr = tmp.str;
unsigned int tmplen = tmp.len;
tmp.str = str;
tmp.len = len;
str = tmpstr;
len = tmplen;
}
return *this;
}
bool isEmpty() const noexcept {
return (len == 0);
}
unsigned int length() const noexcept {
return len;
}
const char* toChars() const {
char* temp = new char[len + 1];
for(unsigned int c = 0; c < len; ++c) {
temp[c] = str[c];
}
temp[len] = '\0';
return temp;
}
};
int main()
{
String t{"Boo is snoring"};
const char *chars = t.toChars();
cout << "t.len : " << t.length() << endl << "toChar() : " << chars << endl;
delete[] chars;
return 0;
}
Хотя более простой способ реализации toChars()
будет выглядеть так:
#include <iostream>
using namespace std;
class String {
public:
char* str = nullptr;
unsigned int len = 0;
String() = default;
String(const char* chars) {
if (chars) {
unsigned int i = 0;
while (chars[i]) {
++i;
}
len = i;
str = new char[len + 1];
for(int j = 0; j < len; ++j) {
str[j] = chars[j];
}
str[len] = '\0';
}
}
String(const String& s) {
if (!s.isEmpty()) {
len = s.len;
str = new char[len + 1];
for(int i = 0; i < len; ++i){
str[i] = s.str[i];
}
str[len] = '\0';
}
}
~String() noexcept {
delete[] str;
}
String& operator=(const String &s) {
if (&s != this) {
String tmp(s);
char *tmpstr = tmp.str;
unsigned int tmplen = tmp.len;
tmp.str = str;
tmp.len = len;
str = tmpstr;
len = tmplen;
}
return *this;
}
bool isEmpty() const noexcept {
return (len == 0);
}
unsigned int length() const noexcept {
return len;
}
const char* toChars() const noexcept {
return str ? str : "";
}
};
int main()
{
String t{"Boo is snoring"};
cout << "t.len : " << t.length() << endl << "toChar() : " << t.toChars() << endl;
return 0;
}