101 Востаннє редагувалося FakiNyan (28.09.2014 20:55:45)

Re: Як створити екземпляр класу і як додати в нього конструктора?

koala написав:

Можу тільки порадити викинути це лайно на смітник і поставити собі компілятор :(

Так в мене ж звичайна VS2013 ultimate.....
UPD: ОООО, все ок, то просто я  компілив з опцією Release, з Debug виводить от що
http://не-дійсний-домен/bRzu7/cbadd85702.png

102

Re: Як створити екземпляр класу і як додати в нього конструктора?

стандартна  помилка - поліз  до неіснуючого  адресу   памяті

103

Re: Як створити екземпляр класу і як додати в нього конструктора?

caballero написав:

стандартна  помилка - поліз  до неіснуючого  адресу   памяті

може до захищенної від запису пам'яті?

104 Востаннє редагувалося koala (28.09.2014 21:03:03)

Re: Як створити екземпляр класу і як додати в нього конструктора?

Звісно до захищенної - в область констант.
А чого реліз так реагував - гадки не маю. Якась надважка оптимізація з урахуванням того, що виникла UB.

105

Re: Як створити екземпляр класу і як додати в нього конструктора?

звичайно - коли  память не  виділена  програмі - вона  захищена

106

Re: Як створити екземпляр класу і як додати в нього конструктора?

компілятор  би  видав  помилку   компіляції  якби  проблема   в   константах

107

Re: Як створити екземпляр класу і як додати в нього конструктора?

компілятор  би  видав  помилку   компіляції  якби  проблема   в   константах

рантайм помилки не стосуються компілятора

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

108

Re: Як створити екземпляр класу і як додати в нього конструктора?

koala написав:

розгляньте ситуацію
MyClass MyClass::operator + ( const MyClass& operand ) const;
...
MyClass a = 1, b = 1, c = a + b;
Тут створюється (для повернення значення з operator +) тимчасовий об'єкт типу MyClass, який здохне одразу після копіювання в c. Тому варто не копіювати значення з нього, а просто перебирати - у вашому випадку це буде (так писати трохи неправильно, але для розуміння поки так)

MyString(MyString&& copy)
{
  str = copy.str;
}

І розберіться з модифікатором const - це дуже важлива річ, коли мова йде про посилання.

З const наче розібрався, ось цей запис

MyClass MyClass::operator + ( const MyClass& operand ) const;

значить слідуюче:

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

Я зрозумів

c = a + b;

Спочатку, майбуть, створюється C, після чого у об'єкта А викликається operator+, котрий приймає посилання на об'єкт B, після чого він проводить потрібні операції та повертає новий об'єкт MyClass.
Далі у об'єкта C спрацьовує конструктор копіювання(?), котрий копіює дані тимчасового об'єкта в себе, ну типу робиться таким самим, як і тимчасовий об'єкт, котрого ми отримали після виклику operator+.
Ну а потім тимчасовий об'єкт, як ви написали - здихає.

І от в мене два питання, спочатку нубське, котре зародилось під час написання цього поста.
При c=(a+b) у об'єкта C викликається конструктор копіювання, чи operator= ? Чому так?

І якщо ми робимо

MyString(MyString&& copy)
{
  str = copy.str;
}

А copy здихає, то це ж значить, що в нього викличеться деструктор, котрий звільний пам'ять, на котру тепер вказує str?
І що за &&? Посилання на посилання? Як це так?
Як компілятор розуміє, коли що викликати: конструктор переміщення, конструктор копіювання, чи operator=?

109

Re: Як створити екземпляр класу і як додати в нього конструктора?

FakiNyan написав:

І от в мене два питання, спочатку нубське, котре зародилось під час написання цього поста.
При c=(a+b) у об'єкта C викликається конструктор копіювання, чи operator= ? Чому так?

Ще раз:

a = x; //a.operator=
ClassName b( x ); // b.ClassName(...)
ClassName  b = x; // b.ClassName(...) !!!

При оголошенні знак = означає те саме, що й дужки; це зроблено для того, щоб не викликати дві функції (типовий конструктор і operator=), які, по суті, роблять те саме, що й конструктор з одним параметром.

FakiNyan написав:

І якщо ми робимо

MyString(MyString&& copy)
{
  str = copy.str;
}

А copy здихає, то це ж значить, що в нього викличеться деструктор, котрий звільний пам'ять, на котру тепер вказує str?

Вітаю, ви пройшли перший рівень :) Так, такий оператор дійсно некоректний. Коректно буде зробити

std::swap( str, copy.str );

і хай деструктор copy звільняє старий str.

FakiNyan написав:

І що за &&? Посилання на посилання? Як це так?

Це новий тип посилань в C++11 - посилання на тимчасовий об'єкт (xvalue). Вираз a+b створює об'єкт, який в C++98 не гідний ні для чого, окрім копіювання в інший об'єкт. В таких випадках в C++11 буде викликаний конструктор переміщення чи оператор присвоювання переміщення, якщо вони визначені.

FakiNyan написав:

Як компілятор розуміє, коли що викликати: конструктор переміщення, конструктор копіювання, чи operator=?

Якщо щось створюється - то конструктор, якщо ні - то оператор =. Якщо операнд цих функцій - тимчасовий об'єкт (xvalue), то переміщення, якщо ні - то копіювання. Детальніше в стандарті.

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

110 Востаннє редагувалося FakiNyan (29.09.2014 20:56:57)

Re: Як створити екземпляр класу і як додати в нього конструктора?

чуєте, а як працює компіляторський operator=?
Просто біда в тому, що от такий кід видає помилку, я вважаю, що ця помилка через спробу звільнити вже звільнену пам'ять

{
        MyString mys = "abcdabe";
        MyString mys1;
        mys1 = mys;

        std::cout << mys1 << std::endl;
        std::cout << mys << std::endl;
    }

Але при звільнені пам'яті я ж пишу, де саме я її звільняю, і от адреси чомусь різні......

MyString::~MyString()
    {
        std::cout << "deleting at: " << &str << std::endl;
        delete[] str; //очищуємо місце, котре виділялось під оті ваші стрічки
    }

UPD: можете вже не відповідати, мені вже пояснили, що я там виводжу адресу вказівника, і ті два вказівника обох об'єктів вказують на одну й ту саму пам'ять, саме тому й звільняється два рази одна й та сама пам'ять

111 Востаннє редагувалося FakiNyan (30.09.2014 22:25:17)

Re: Як створити екземпляр класу і як додати в нього конструктора?

Ну я от так написав, але чомусь не бачу в консольці, щоб там писалось про конструктори переміщення і оператор присвоєння переміщення, зато наглядно бачу, що тимчасовий об'єкт таки створюється, бо 4 рази викликається деструктор

MyString(MyString&& move)
    {
        std::cout << "moving constructor" << std::endl;
    }

    MyString& operator=(MyString&& move)
    {
        std::cout << "move assignment" << std::endl;
    }

    MyString operator+(MyString other)
    {
        std::cout << "operator+" << std::endl;
        *this += other.str;
        return MyString(*this);
    }

int main()
{

    {
        MyString mys = "abcdabe";
        MyString mys1 = " rrra";
        MyString mys2 = mys + mys1;

        std::cout << mys2 << std::endl;
    }


    system("pause >> void");
}
Прихований текст

http://не-дійсний-домен/bUn7D/ac81df98b7.png

112

Re: Як створити екземпляр класу і як додати в нього конструктора?

А тепер зробіть їх не inline, будь ласка. І змініть функціональність operator +, щоб він не змінював об'єкт (коли ви пишете a = b + c, ви ж не очікуєте, що b зміниться, правда?)

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

113 Востаннє редагувалося FakiNyan (01.10.2014 00:08:34)

Re: Як створити екземпляр класу і як додати в нього конструктора?

koala написав:

А тепер зробіть їх не inline, будь ласка. І змініть функціональність operator +, щоб він не змінював об'єкт (коли ви пишете a = b + c, ви ж не очікуєте, що b зміниться, правда?)

Так піде?

MyString operator+(MyString other)
    {
        std::cout << "operator+" << std::endl;
        MyString tmp(str);
        tmp += other.str;
        return tmp;
    }

Я навіть не знаю, що значить inline. Ну я погуглив, і то наче коли перед методом стоїть модифікатор inline, в мене нема такого xD
І той, ото я просто тупив, коли писав operator+.
І цей, чуйте, плюс до всього, поясніть мені за типи, котрі може повертати функція. Під типами я маю на увазі 3 випадки, покажчик, посилання, та просто тип.
Наприклад, от тут

*MyClass func(){}

Повертається адреса в пам'яті, котра містить адресу, по котрій знаходяться дані.
Ось тут

MyClass& func(){}

Повертається адреса, по котрій знаходяться дані
А от тут що повертається?

MyClass func(){}

UPD: ось тут же спочатку створюється об'єкт tmp, потім створюється його копія, та повертається з функції, після чого об'єкт tmp зникає? Якщо так, то я вже знайшов одну відмінність між повертанням MyClass& та MyClass

MyString operator+(MyString other)
    {
        std::cout << "operator+" << std::endl;
        MyString tmp(str);
        tmp += other.str;
        return tmp;
    }

114

Re: Як створити екземпляр класу і як додати в нього конструктора?

Якщо тіло функції записано прямо в класі

class ...{
  ...
  int func(){
    ...
  }
  ...
}

то вона вважається inline.

Подякували: 0xDADA11C71

115

Re: Як створити екземпляр класу і як додати в нього конструктора?

ну от, в класі написав

    MyString(MyString&&);

    MyString& operator=(MyString&&);

а поза класом

MyString::MyString(MyString&& move)
{
    std::cout << "moving constructor" << std::endl;
}

MyString& MyString::operator=(MyString&& move)
{
    std::cout << "move assignment" << std::endl;
    MyString ms;
    return ms;
}

наче нічого не змінилось при виконанні того кода

int main()
{

    {
        MyString mys = "abcdabe";
        MyString mys1 = " rrra";
        MyString mys2 = mys + mys1;

        std::cout << mys2 << std::endl;
    }

    system("pause >> void");
}

116

Re: Як створити екземпляр класу і як додати в нього конструктора?

Можете ще раз повністю клас викласти?

117

Re: Як створити екземпляр класу і як додати в нього конструктора?

#include <cstdlib>
#include <iostream>
#include <cstdio>

class MyString
{
public:
    friend std::ostream& operator<<(std::ostream& os, const MyString& ms);

    MyString::MyString(){}

    MyString::MyString(char* str)
    {
        int length = Length(str);
        char* s1 = new char[length + 1];
        for (int i = 0; i < length; i++)
        {
            s1[i] = str[i];
        }
        s1[length] = '\0';
        MyString::str = s1;
    }
    MyString::~MyString()
    {
        std::cout << "deleting at: " << int(str) << " value: "<< str << std::endl;
        delete[] str; //очищуємо місце, котре виділялось під оті ваші стрічки
    }

    MyString::MyString(MyString& copy)
    {
        int length = copy.Length();
        str = new char[length + 1];

        for (int i = 0; i < length; i++)
        {
            str[i] = copy.str[i];
        }

        str[length] = '\0';
    }

    MyString(MyString&&);

    MyString& operator=(MyString&&);

    MyString operator+(MyString other)
    {
        std::cout << "operator+" << std::endl;
        MyString tmp(str);    
        tmp += other.str;
        return tmp;
    }

    void operator+=(char* str)
    {
        int length = Length() + Length(str); // отримуємо довжину нової строки
        char *s = new char[length + 1]; // для термінатора
        for (int i = 0; i < Length(); i++)// записуємо в нову строку те, що вже було
        {
            s[i] = MyString::str[i];
        }
        for (int i = 0; i < Length(str); i++)// дописуємо те, що треба додати
        {
            s[i + Length()] = str[i];
        }
        delete[] MyString::str;
        MyString::str = s;// присвоюємо старому вказівнику на стару
        MyString::str[length] = '\0'; //- це термінатор
    }

    int Find(char* subString)
    {
        int subStringLength = Length(subString);
        for (int i = 0; i < Length(); i++)
        {
            int index = -1;
            for (int j = 0; j < subStringLength; j++)
            {
                if (str[i] == subString[j])
                {
                    if (j == 0)
                    {
                        index = i;
                    }
                    if (j == subStringLength - 1)
                    {
                        return index;
                    }
                    else
                        if (i != Length() - 1)
                        {
                        i++;
                        continue;
                        }
                }
                else
                {
                    break;
                }
            }
        }
        return -1;
    }

    void Remove(int startIndex, int count)
    {
        int newStrLength = Length() - count;
        char* newStr = new char[newStrLength + 1];

        for (int i = 0; i < newStrLength; i++)
        {
            if (i < startIndex)
                newStr[i] = str[i];
            else
                newStr[i] = str[i + count];
        }

        newStr[newStrLength] = '\0';
        delete[] str;
        str = newStr;
    }

    int Length()
    {
        int i = 0;
        while (str[i] != '\0')
        {
            i++;
        }
        return i;
    }

    int Length(char* str)
    {
        int i = 0;
        while (str[i] != '\0')
        {
            i++;
        }
        return i;
    }

private:
    char *str;
};

std::ostream& operator<<(std::ostream& os, const MyString& ms)
{
    os << ms.str;
    return os;
}

MyString::MyString(MyString&& move)
{
    std::cout << "moving constructor" << std::endl;
}

MyString& MyString::operator=(MyString&& move)
{
    std::cout << "move assignment" << std::endl;
    MyString ms;
    return ms;
}

int main()
{

    {
        MyString mys = "abcdabe";
        MyString mys1 = " rrra";
        MyString mys2 = mys + mys1;

        std::cout << mys2 << std::endl;
    }

    system("pause >> void");
}

118

Re: Як створити екземпляр класу і як додати в нього конструктора?

Не з проста існує думка,що Страуструп створив С++ щоб ускладнити життя програмістам і заодно підняти їм зарплатню.

119

Re: Як створити екземпляр класу і як додати в нього конструктора?

VTrim написав:

Не з проста існує думка,що Страуструп створив С++ щоб ускладнити життя програмістам і заодно підняти їм зарплатню.

Звісно що так. З Фортраном, Коболом і Алголом життя здавалось казкою програмісту 70-х років.

120

Re: Як створити екземпляр класу і як додати в нього конструктора?

Все, я пішов в дипресію читати стандарт...