1

Тема: Конструктор копіювання не працює, свій клас string, конкатенація.

Пишу свій клас string за уроками на ютубі. Назвав я його "nyzka", а його розмір - то "sz". Нехай мене за це вибачать.

Проблема полягає у тому,  що наприкінці виконання методу перевантаження оператора '+'
компілятор мав би перейти у конструктор копіювання. Проте цього не відбувається,
а компілятор переходить одразу у деструктор.
    Я вже задовбався гіпнотизувати браузер у пошуках вирішення. Я не можу продовжити своє навчання через це.
    Якби я сумнівався у правильності свого коду я б сюди не написав. Допоможііть! %)

Проблема у виконанні операції     test = text_1 + text_2;

#include<iostream>
using namespace std;

////    CREATING OWN CLASS LIKE "STRING" NAMED "NYZKA"    ////

class nyzka
{
    char* str;
    int sz;

public:
            // -V- default constructor
    nyzka()
    {
        this->str = nullptr;
        this->sz = 0;
    }
            // -V- constructor
    nyzka(const char* str)
    {
        this->sz = strlen(str);
        this->str = new char[sz+1];
        for (int i = 0; i < sz; i++) { this->str[i] = str[i]; }
        this->str[sz] = '\0';
    }
            // -V- copying constructor
    nyzka(const nyzka& other)
    {
        this->sz = other.sz;
        this->str = new char[sz + 1];
        for (int i = 0; i < sz; i++) { this->str[i] = other.str[i]; }
        this->str[sz] = '\0';
    }
            // -V-  +  operator overload
    nyzka& operator + (const nyzka& other)
    {
        nyzka newstr;
        newstr.sz = strlen(this->str) + strlen(other.str);
        newstr.str = new char[newstr.sz + 1];
        int i;
        for (i = 0; i < strlen(this->str); i++)
        {
            newstr.str[i] = this->str[i];
        }
        for (int j = 0; i < newstr.sz; j++, i++)
        {
            newstr.str[i] = other.str[j];
        }
        newstr.str[newstr.sz] = '\0';
        return newstr;
    }
            // -V-  =  operator overload
    nyzka& operator = (nyzka& other)
    {
        if(this->str!=nullptr)
            delete[] this->str;
        this->sz = other.sz;
        this->str = new char[sz + 1];
        for (int i = 0; i < sz; i++) { this->str[i] = other.str[i]; }
        this->str[sz] = '\0';
        return *this;
    }
            // -V- [i] operator constructor
    void display()
    {
        cout << endl << endl << str << endl << "size = " << sz << endl;
    }
            // -V- destructor
    ~nyzka()
    {
        delete[] this->str;
    }
};

int main() //::::
{
    nyzka text_1 = "Snake";
    text_1.display();

    nyzka text_2 = "Kytska";
    text_2.display();

    nyzka test;
    test = text_1 + text_2;
    test.display();
}

2 Востаннє редагувалося koala (17.10.2020 09:38:58)

Re: Конструктор копіювання не працює, свій клас string, конкатенація.

На YouTube більше ніж одні уроки, тому посилання нічого не дає. Хоча в цілому навчатися програмувати виключно за відео, без книжки - це якось дивно.
Клас nyzka має два коректних стани, з виділеною пам'яттю на sz+1 і з sz=0, str=nullptr. Але при цьому ви спокійно викликаєте strlen(str). strlen(nullptr) дасть чудовий SEGFAULT. Так само ви не перевіряєте в деструкторі на nullptr, але це вже можна в C++11 пережити.
Далі, постарайтеся уникати однакових назв параметрів і членів класу.

По суті ж вашого питання - там немає жодного копіювання, відповідно, немає виклику конструктора. Спробуйте пояснити детальніше, чому ви вирішили, що воно там має бути.

3 Востаннє редагувалося wander (17.10.2020 01:32:50)

Re: Конструктор копіювання не працює, свій клас string, конкатенація.

koala написав:

Так само ви не перевіряєте в деструкторі на nullptr, але це вже можна в C++11 пережити.

Гм, а що там такого в С++11?

ISO/IEC 14882:1998 написав:

3.7.3.2\3
The value of the first argument supplied to one of the deallocation functions provided in the standard
library may be a null pointer value; if so, the call to the deallocation function has no effect.
[...]

Подякували: mikesteinar, leofun012

4 Востаннє редагувалося koala (17.10.2020 08:07:45)

Re: Конструктор копіювання не працює, свій клас string, конкатенація.

Ну раз навіть у C++98 воно так, то в C++11 й поготів.

mikesteinar, вам, мабуть, буде цікаво дізнатися, що strlen всередині виглядає приблизно як

for(int i=0;;++i)
  if(str[i]=='\0')
    return i;

Тобто цикл

for(;i<strlen(s);)
    ...

це насправді вкладені цикли - ви кожного разу перевіряєте довжину. Але у вас же sz завжди потрібного розміру, то можете ним користатися. Ну і решту функцій, таких як strcpy і strcat, використовувати.

А, і ще: випишіть інваріанти, тобто властивості, які гарантовано зберігаються для вашої "низки". Наприклад,
"якщо sz>0, то strlen(str) завжди дорівнює sz; якщо sz==0, то str може бути nullptr, а може вказувати на байт '\0'" тощо. Інкапсуляція якраз і існує для того, щоб клас підтримував інваріанти у внутрішньому стані.

Подякували: mikesteinar1

5

Re: Конструктор копіювання не працює, свій клас string, конкатенація.

помилка нумер один
https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/Ordinary_bicycle01.jpg/200px-Ordinary_bicycle01.jpg
помилка нумер два
http://3.bp.blogspot.com/-5CffzgEr0Ps/VMUQciSKo0I/AAAAAAAAACM/lsJS8KZBL_E/s1600/string.png

6

Re: Конструктор копіювання не працює, свій клас string, конкатенація.

ur_naz написав:

помилка нумер один

Це не помилка, це навчальне завдання.
Звісно, в реальних проєктах так робити не можна, але для навчання - чому б ні?

7

Re: Конструктор копіювання не працює, свій клас string, конкатенація.

koala написав:

На YouTube більше ніж одні уроки, тому посилання нічого не дає. Хоча в цілому навчатися програмувати виключно за відео, без книжки - це якось дивно.
Клас nyzka має два коректних стани, з виділеною пам'яттю на sz+1 і з sz=0, str=nullptr. Але при цьому ви спокійно викликаєте strlen(str). strlen(nullptr) дасть чудовий SEGFAULT. Так само ви не перевіряєте в деструкторі на nullptr, але це вже можна в C++11 пережити.
Далі, постарайтеся уникати однакових назв параметрів і членів класу.

Спробую відповісти по порядку.

1. Так, зараз, можна сказати, що я вивчаю за уроками з одного каналу за великим рахунком. Хоч іноді додаткову інфу шукаю і деінде. Поки що моя куца англійська не дозволяє мені в достатній мірі користуватись книжками.

2. Хочу уточнити у якому(чи у яких) з блоків мого коду наявні вказані вами помилки. Це для того, щоб я був впевнений, що правильно шукаю.


koala написав:

По суті ж вашого питання - там немає жодного копіювання, відповідно, немає виклику конструктора. Спробуйте пояснити детальніше, чому ви вирішили, що воно там має бути.

3. Void fun() я спеціально створив, для перевірки роботоздатності конструктора, описаного у блоці  "// -V- copying constructor"
    Свою функцію він виконав.

4. Необхідність його наявності для операції конкатенації я почерпнув тут: https://youtu.be/Y3GGqqXlPQI?t=4659

8

Re: Конструктор копіювання не працює, свій клас string, конкатенація.

koala написав:

Ну раз навіть у C++98 воно так, то в C++11 й поготів.

mikesteinar, вам, мабуть, буде цікаво дізнатися, що strlen всередині виглядає приблизно як

for(int i=0;;++i)
  if(str[i]=='\0')
    return i;

Тобто цикл

for(;i<strlen(s);)
    ...

це насправді вкладені цикли - ви кожного разу перевіряєте довжину. Але у вас же sz завжди потрібного розміру, то можете ним користатися. Ну і решту функцій, таких як strcpy і strcat, використовувати.

А, і ще: випишіть інваріанти, тобто властивості, які гарантовано зберігаються для вашої "низки". Наприклад,
"якщо sz>0, то strlen(str) завжди дорівнює sz; якщо sz==0, то str може бути nullptr, а може вказувати на байт '\0'" тощо. Інкапсуляція якраз і існує для того, щоб клас підтримував інваріанти у внутрішньому стані.


Перевірка у циклі дійсно зайва, дякую. Щодо інваріантів не до кінця зрозумів, буду розбиратись самостійно.

9 Востаннє редагувалося koala (17.10.2020 11:45:54)

Re: Конструктор копіювання не працює, свій клас string, конкатенація.

mikesteinar написав:

Хочу уточнити у якому(чи у яких) з блоків мого коду наявні вказані вами помилки.

В operator +:

        newstr.sz = strlen(this->str) + strlen(other.str);

Ви не знаєте, які саме низки будуть подані на вхід цієї функції. А раптом із nullptr-ами?

nyzka s1;//default constructor
nyzka s2;//default constructor
nyzka s3 = s1+s2;//WTF!

В конструкторі:

this->sz = strlen(str);

Праворуч - параметр чи член класу? Це не помилка, але краще уникати цього.

Конструктор копіювання не потрібен для операції конкатенації, це взагалі з різних галузей. Може знадобитися, може не знадобитися. У вас там інша помилка - ви повертаєте посилання на локальну зміну.

    nyzka& operator + (const nyzka& other)
    {
        nyzka newstr;
        ...
        return newstr;
    }

newstr припинить існування при виході з operator +, а посилання на нього повернеться, що станеться при спробі використати це посилання - невідомо.

Подякували: mikesteinar1

10

Re: Конструктор копіювання не працює, свій клас string, конкатенація.

koala написав:

Конструктор копіювання не потрібен для операції конкатенації, це взагалі з різних галузей. Може знадобитися, може не знадобитися. У вас там інша помилка - ви повертаєте посилання на локальну зміну.

    nyzka& operator + (const nyzka& other)
    {
        nyzka newstr;
        ...
        return newstr;
    }

newstr припинить існування при виході з operator +, а посилання на нього повернеться, що станеться при спробі використати це посилання - невідомо.

За логікою newstr буде знищено в будь-якому разі. То як же його передати?

11

Re: Конструктор копіювання не працює, свій клас string, конкатенація.

За значенням, звісно.
І тоді знадобиться - так - конструктор копіювання.

Подякували: mikesteinar1

12

Re: Конструктор копіювання не працює, свій клас string, конкатенація.

koala написав:

За значенням, звісно.
І тоді знадобиться - так - конструктор копіювання.

Господи!  Замість

   nyzka& operator + (const nyzka& other)

варто було вказати

   nyzka operator + (const nyzka& other)

і все запрацювало. Навіть в уроці амперсант відсутній.
Логічно, адже копіювання відбувається саме при передачі за значенням.
Дякую, проблема вирішена.

13

Re: Конструктор копіювання не працює, свій клас string, конкатенація.

яке це навчання? це якась диверсія...

14

Re: Конструктор копіювання не працює, свій клас string, конкатенація.

mikesteinar написав:
koala написав:

На YouTube більше ніж одні уроки, тому посилання нічого не дає. Хоча в цілому навчатися програмувати виключно за відео, без книжки - це якось дивно.
Клас nyzka має два коректних стани, з виділеною пам'яттю на sz+1 і з sz=0, str=nullptr. Але при цьому ви спокійно викликаєте strlen(str). strlen(nullptr) дасть чудовий SEGFAULT. Так само ви не перевіряєте в деструкторі на nullptr, але це вже можна в C++11 пережити.
Далі, постарайтеся уникати однакових назв параметрів і членів класу.

Спробую відповісти по порядку.

1. Так, зараз, можна сказати, що я вивчаю за уроками з одного каналу за великим рахунком. Хоч іноді додаткову інфу шукаю і деінде. Поки що моя куца англійська не дозволяє мені в достатній мірі користуватись книжками.

2. Хочу уточнити у якому(чи у яких) з блоків мого коду наявні вказані вами помилки. Це для того, щоб я був впевнений, що правильно шукаю.


koala написав:

По суті ж вашого питання - там немає жодного копіювання, відповідно, немає виклику конструктора. Спробуйте пояснити детальніше, чому ви вирішили, що воно там має бути.

3. Void fun() я спеціально створив, для перевірки роботоздатності конструктора, описаного у блоці  "// -V- copying constructor"
    Свою функцію він виконав.

4. Необхідність його наявності для операції конкатенації я почерпнув тут:

офтопна мова