Jun 3, 2022 at 7:18am UTC
Hi everybody,
i've trained to write a std::string clone [whole code at the bottom]
Then, i wanted to use this class as a vector member. Ive written some code like the copy and move constructor, but it seems to be be incorrect, i do get overflows if i add elements to my std::vector<String> container.
Constructors meant:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
String(const String &cp) {
std::cout << "copy constructor" << "\n" ;
if (initialized)
free(_value);
_value = (char *) malloc(cp._len());
_value = strdup(cp._value);
}
String (const String&& other) {
std::cout << "move constructor" << "\n" ;
if (initialized)
free(_value);
_value = (char *) malloc(other._len());
_value = strdup(other._value);
}
This part might be incorrect but i dont get why.
Do you know how to make my code work?
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
class String {
char *_value;
bool initialized = false ;
char * _substr(const char *src, size_t m, size_t n) {
size_t len = n - m;
char *dest = (char *)malloc(sizeof (char ) * (len + 1));
for (size_t i = m; i < n && (*(src + i) != '\0' ); i++)
{
*dest = *(src + i);
dest++;
}
*dest = '\0' ;
return dest - len;
}
size_t _len() const {
size_t res{};
while (_value[res++]);
return res - 1;
}
public :
String(const char *val) {
_value = (char *) malloc(sizeof val / sizeof *val);
if (_value == nullptr )
throw std::runtime_error("error while allocating memory" );
strcpy(_value, val);
initialized = true ;
}
String(char *val) {
_value = (char *) malloc(sizeof val / sizeof *val);
if (_value == nullptr )
throw std::runtime_error("error while allocating memory" );
strcpy(_value, (const char *) val);
initialized = true ;
}
String() {
_value = (char *) malloc(sizeof (char ));
if (_value == nullptr )
throw std::runtime_error("error while allocating memory" );
strcpy(_value, "" );
initialized = true ;
}
// Copy - Constructor IMPORTANT
String(const String &cp) {
std::cout << "copy constructor" << "\n" ;
if (initialized)
free(_value);
_value = (char *) malloc(cp._len());
_value = strdup(cp._value);
}
String (const String&& other) {
std::cout << "move constructor" << "\n" ;
if (initialized)
free(_value);
_value = (char *) malloc(other._len());
_value = strdup(other._value);
}
char &operator [](int index) const {
if (index >= 0)
return *(_value + index);
return *(_value + (_len() - (index * -1)));
}
const char *c_str() const {return _value;}
const unsigned long long length() const {return _len();};
void push_back(char q);
void pop_back();
String &append(const char *);
String &operator +=(const char *app_str) {
return append(app_str);
}
String &insert(int , const char *);
String substr(size_t begin, size_t end) {return String{_substr( _value, begin, end)};}
long long find_first(char ) const ;
std::vector<size_t> findall(char ) const ;
std::vector<size_t> findall(const char *);
long long find_first(const char *);
long long find_last(char );
long long find_last(const char *);
std::vector<const char *> split(char );
std::vector<const char *> split(const char *);
~String() {free(_value);}
}
Thanks in advance
Luke
Last edited on Jun 3, 2022 at 7:25am UTC
Jun 3, 2022 at 7:33am UTC
Make sure you allocate enough space to store the null character.
Don't use sizeof on char pointers. Instead use std::strlen to get the length of the string.
You should not need to have a variable named initialized. If there are situations when the _value pointer should not point to anything just set it to null. Passing null to free is safe and will do nothing so you don't need to check.
Last edited on Jun 3, 2022 at 7:34am UTC
Jun 3, 2022 at 8:17am UTC
Why do you check initialization in constructors ? The this
is created there; how could it have been used "before"?
Why is the move constructor identical to copy constructor? Yes, it can be, but the idea of move is to be more efficient than copy.
Jun 3, 2022 at 3:58pm UTC
Looking at your code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
String(const String &cp) {
std::cout << "copy constructor" << "\n" ;
if (initialized) // wrong test, we know we're not initialized
free(_value);
_value = (char *) malloc(cp._len() + 1); // either, malloc(stdlen(cp._value) + 1); strcpy(_value, cp._value);
_value = strdup(cp._value); // or, strdup(cp._value), not both
}
String (const String&& other) { // const is wrong, it shouldn't be there
std::cout << "move constructor" << "\n" ;
if (initialized) // again, wrong, we know we're not initialized
free(_value);
_value = (char *) malloc(other._len());
_value = strdup(other._value);
// do the move from other to here
_value = other._value;
other._value = nullptr ;
}
Last edited on Jun 3, 2022 at 4:01pm UTC
Jun 3, 2022 at 5:12pm UTC
also move constructor shouldn't cause an exception in any cases and should be marked as noexcept.
copy constructor can also be coded in terms of constructor(const char*) so code isn't duplicated.
Last edited on Jun 3, 2022 at 5:13pm UTC