The task is to create a string class. I registered the constructors, overloaded the operations, and the program seems to work fine, but in the last line there is an error of execution "CRT detected I attach the class header file, if necessary I can attach the implementation.

#pragma once #include <iostream> using namespace std; class my_string { private: char *string_chars; size_t len; public: my_string(const char *string_chars); my_string(const size_t len); my_string(const my_string &obj); my_string(); ~my_string() { delete[] this->string_chars; } my_string operator+(const my_string &b) const; my_string operator+(const char *b) const; my_string &operator=(const my_string &b); my_string &operator=(const char *b); my_string &operator+=(const my_string &b); my_string &operator+=(const char *b); bool operator<(const my_string &b) const; bool operator<(const char *b) const; bool operator>(const my_string &b) const; bool operator>(const char *b) const; bool operator==(const my_string &b) const; bool operator==(const char *b) const; bool operator!=(const my_string &b) const; bool operator!=(const char *b) const; void print() const { cout << this->string_chars << endl; } const char *get_str() const { return this->string_chars; } size_t get_len() const { return this->len; } size_t first_sym(const char a) const; }; 

UPD: Attached implementation

 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string.h> #include "String.h" using namespace std; my_string::my_string(const char *string_chars) { this->len = strlen(string_chars); this->string_chars = new char[this->len + 1]; strcpy(this->string_chars, string_chars); this->string_chars[this->len] = 0; } my_string::my_string(const size_t len) { this->len = len; this->string_chars = new char[this->len + 1]; for (size_t i = 0; i <= len; i++) { this->string_chars[i] = 0; } } my_string::my_string(const my_string &obj) { strcpy(this->string_chars, obj.get_str()); this->len = obj.get_len(); } my_string::my_string() { this->len = 0; this->string_chars = new char[2]; for (int i = 0; i < 2; i++) { this->string_chars[i] = 0; } } my_string my_string::operator+(const my_string &b) const { size_t len = this->len + b.get_len(); char *result = new char[len + 1]; strcpy(result, this->string_chars); strcat(result, b.string_chars); result[len] = 0; my_string *res = new my_string(result); delete[] result; return *res; } my_string my_string::operator+(const char *b) const { size_t len = this->len + strlen(b); char *result = new char[len + 1]; strcpy(result, this->string_chars); strcat(result, b); result[len] = 0; my_string *res = new my_string(result); delete[] result; return *res; } my_string &my_string::operator=(const my_string &b) { if (&b != this) { this->len = b.get_len(); strcpy(this->string_chars, b.string_chars); } return *this; } my_string &my_string::operator=(const char *b) { if (b != this->string_chars) { this->len = strlen(b); strcpy(this->string_chars, b); } return *this; } my_string &my_string::operator+=(const my_string &b) { this->len += b.get_len(); strcat(this->string_chars, b.string_chars); return *this; } my_string &my_string::operator+=(const char *b) { this->len += strlen(b); strcat(this->string_chars, b); return *this; } bool my_string::operator<(const my_string &b) const { if (strcmp(b.string_chars, this->string_chars)) { return true; } else { return false; } } bool my_string::operator<(const char *b) const { if (strcmp(b, this->string_chars)) { return true; } else { return false; } } bool my_string::operator>(const my_string &b) const { if (strcmp(this->string_chars, b.string_chars)) { return true; } else { return false; } } bool my_string::operator>(const char *b) const { if (strcmp(this->string_chars, b)) { return true; } else { return false; } } bool my_string::operator==(const my_string &b) const { if (!strcmp(this->string_chars, b.string_chars) && this->len == b.len) { return true; } else { return false; } } bool my_string::operator==(const char *b) const { if (!strcmp(this->string_chars, b) && this->len == strlen(b)) { return true; } else { return false; } } bool my_string::operator!=(const my_string &b) const { if (abs(strcmp(this->string_chars, b.string_chars)) || this->len != b.len) { return true; } else { return false; } } bool my_string::operator!=(const char *b) const { if (abs(strcmp(this->string_chars, b)) || this->len != strlen(b)) { return true; } else { return false; } } size_t my_string::first_sym(const char a) const { char *sym = strchr(this->string_chars, a); if (sym != nullptr) { return sym - this->string_chars; } return -1; } 

    1 answer 1

    Such classes where memory is dynamically allocated should be explicitly defined by the copy constructor. It is not declared in your class, and therefore its absence may be the cause of the error, since the copy constructor implicitly created by the compiler simply copies the values ​​of the class members in turn, which may result in two class objects having pointers pointing to the same area of ​​memory that the destructors of these objects will eventually try to delete twice.

    This constructor with parameter

     my_string(const int len); ^^^^ 

    it would be better to announce how

     my_string( size_t len ); ^^^^^^ 

    These operators

     my_string &operator+(const my_string &b) const; my_string &operator+(const char *b) const; 

    declared incorrectly. Since the class member functions themselves are constant, the class object, which is located on the left side of the + sign, does not change. It follows that operators return a reference to temporary objects created inside operators, which leads to undefined program behavior.

    This feature

     char *get_str() const { return this->string_chars; } 

    since it is better to declare a constant with the return value const char * , or to overload this function for constant and non-constant objects.

    The definition of this function

     int first_sym(const char a) const { return strchr(this->string_chars, a) - this->string_chars; } 

    incorrectly, since in the absence of the a character in the string, the strchr function will return a NULL pointer. In addition, the return type must not be int , but at least ptrdiff_t . Of course, it would be better to declare the size_t return type, and if the character is not found in the string, then return the value -1 .

    As for the error that arises, it most likely arises due to incorrect implementations of operators that you didn’t give in your question, and the proposal that resulted in the execution of this error is unknown. For example, it is possible that you forgot to allocate memory for the terminating zero in summation operators, or "skip" this zero when copying rows.


    EDIT: Since you changed your answer, correcting some of the flaws that I pointed out (which is a bad idea, as this can lead to a mismatch between the answer and the question), and supplemented it with implementation,

    In this constructor, the last sentence is superfluous, and can be deleted.

     my_string::my_string(const char *string_chars) { this->len = strlen(string_chars); this->string_chars = new char[this->len + 1]; strcpy(this->string_chars, string_chars); this->string_chars[this->len] = 0; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ } 

    This constructor can be written easier.

     my_string::my_string(const size_t len) { this->len = len; this->string_chars = new char[this->len + 1](); } 

    It is better to declare this constructor with the explicit function specifier.

     explicit my_string::my_string( size_t len) { this->len = len; this->string_chars = new char[this->len + 1](); } 

    Otherwise, it turns out that you can add strings to integers due to the presence of this conversion constructor.

    Or it would be even better to declare it with the second parameter, which defines the placeholder character. For example,

     #include <cstring> //... my_string::my_string( size_t len, char c ) { this->len = len; this->string_chars = new char[this->len + 1](); std::memset(this->string_chars, ( unsigned char )c, len ); } 

    This copy constructor is not valid.

     my_string::my_string(const my_string &obj) { strcpy(this->string_chars, obj.get_str()); this->len = obj.get_len(); } 

    The memory where the string is copied was not allocated.

    In this default constructor, it is enough to allocate memory for one character.

     my_string::my_string() { this->len = 0; this->string_chars = new char[1](); } 

    This operator is incorrect and can lead to a memory leak. There is no need to create an object in dynamic memory.

     my_string my_string::operator+(const my_string &b) const { size_t len = this->len + b.get_len(); char *result = new char[len + 1]; strcpy(result, this->string_chars); strcat(result, b.string_chars); result[len] = 0; my_string *res = new my_string(result); delete[] result; return *res; } 

    It can be defined as follows.

     my_string my_string::operator+(const my_string &b) const { size_t len = this->len + b.get_len(); char *result = new char[len + 1]; strcpy(result, this->string_chars); strcat(result, b.string_chars); my_string res(result); delete[] result; return res; } 

    The same is true for the second overloaded operator + .

    Simple and compound assignment operators are incorrectly defined. In them, in general, there is an overflow of allocated memory. You must delete the previously created string, if it is not equal to the length assigned, and create a new one with the appropriate length.

    All comparison operators can be written easier. Moreover, they are also written incorrectly. For example, instead of this incorrectly written operator

     bool my_string::operator<(const my_string &b) const { strcmp(b.string_chars, this->string_chars)) { return true; } else { return false; } } 

    Must be

     bool my_string::operator<(const my_string &b) const { return strcmp( this->string_chars, b.string_chars ) < 0; } 
    • my_string &operator+(const my_string &b) const; my_string &operator+(const char *b) const; In this case, how can these operations be reworked so that they do not change the objects for which they are called, but could pass, for example, the result to an assignment operation (by analogy with int variables)? - Dheinamar
    • @Dheinamar They must have the return type not a reference, but simply my_string, that is, it returns a temporary object created in the body of the operators. - Vlad from Moscow