තුන්දෙනාගේ නීතිය කුමක්ද?


2162
  • කුමක්ද කරන්නේ වස්තුවක් පිටපත් අදහස්?
  • මොකක්ද? පිටපතක් ඉදිකිරීමටත් හා පිටපතක් පැවරුම ක්රියාකරු ?
  • ඒවා මා විසින්ම ප්‍රකාශ කිරීමට අවශ්‍ය වන්නේ කවදාද?
  • මගේ වස්තූන් පිටපත් කිරීම වළක්වා ගන්නේ කෙසේද?

53
කරුණාකර කියවන්න මේ මුළු නූල් හා එම c++-faqටැගය විකි ඔබ වසා ඡන්දය පෙර .
sbi

13
Inary ද්විමය: ඔබ ඡන්දය ප්‍රකාශ කිරීමට පෙර අවම වශයෙන් අදහස් දැක්වීමේ සාකච්ඡාව කියවීමට කාලය ගන්න . පෙළ වඩාත් සරල විය, නමුත් එය පුළුල් කරන ලෙස ෆ්‍රෙඩ්ගෙන් ඉල්ලා සිටියේය. එසේම, එය ව්‍යාකරණමය වශයෙන් ප්‍රශ්න හතරක් වන අතර , එය සැබවින්ම එයට අංශ කිහිපයක් සහිත එක් ප්‍රශ්නයක් පමණි. (ඔබ වෙත එකඟ නොවන්නේ නම්, එවිට එහි ම මත එම ප්රශ්න එක් එක් පිළිතුරු දී ඔබගේ ඥානය ඔප්පු අපට ප්රතිඵල මත ඡන්දය දෙන්න.)
රාජරත්නම්

1
ෆ්‍රෙඩ්, C ++ 1x: stackoverflow.com/questions/4782757/… පිළිබඳ ඔබගේ පිළිතුරට රසවත් එකතු කිරීමක් මෙන්න . අපි මේ සමඟ කටයුතු කරන්නේ කෙසේද?
sbi


4
මතක තබා ගන්න, C ++ 11 වන විට, මම සිතන්නේ මෙය පහක රීතියට උසස් කර ඇති බවයි.
paxdiablo

Answers:


1801

හැදින්වීම

C ++ පරිශීලක අර්ථ දක්වන ලද වර්ගවල විචල්‍යයන් අගය අර්ථ නිරූපණයන් සමඟ සලකයි . මෙයින් අදහස් කරන්නේ වස්තූන් විවිධ සන්දර්භයන් තුළ ව්‍යංගයෙන් පිටපත් කර ඇති අතර “වස්තුවක් පිටපත් කිරීම” යන්නෙන් සැබවින්ම අදහස් කරන්නේ කුමක්ද යන්න අප තේරුම් ගත යුතුය.

අපි සරල උදාහරණයක් සලකා බලමු:

class person
{
    std::string name;
    int age;

public:

    person(const std::string& name, int age) : name(name), age(age)
    {
    }
};

int main()
{
    person a("Bjarne Stroustrup", 60);
    person b(a);   // What happens here?
    b = a;         // And here?
}

(ඔබ name(name), age(age)කොටසින් ව්‍යාකූල වී ඇත්නම් , මෙය සාමාජික ආරම්භක ලැයිස්තුවක් ලෙස හැඳින්වේ .)

විශේෂ සාමාජික කාර්යයන්

personවස්තුවක් පිටපත් කිරීම යන්නෙන් අදහස් කරන්නේ කුමක්ද? මෙම mainකාර්යය පැහැදිලි පිටපත් සිදුවීම් දෙකක් පෙන්වයි. ආරම්භ person b(a);කිරීම පිටපත් සාදන්නා විසින් සිදු කරනු ලැබේ . එහි කාර්යය වන්නේ පවතින වස්තුවක තත්වය මත පදනම්ව නැවුම් වස්තුවක් තැනීමයි. පැවරුම පිටපත් පැවරුම් ක්‍රියාකරුb = a විසින් සිදු කරනු ලැබේ . එහි කාර්යය සාමාන්‍යයෙන් මඳක් සංකීර්ණ වේ, මන්ද ඉලක්කගත වස්තුව දැනටමත් යම් වලංගු තත්වයක පවතින බැවින් එය සමඟ කටයුතු කළ යුතුය.

පිටපත් සාදන්නා හෝ පැවරුම් ක්‍රියාකරු (හෝ විනාශ කරන්නා) අප විසින්ම ප්‍රකාශයට පත් කර නොමැති හෙයින්, මේවා අපට ව්‍යංගයෙන් අර්ථ දක්වා ඇත. සම්මතයෙන් උපුටා ගැනීම:

[...] පිටපත් සාදන්නා සහ පිටපත් පැවරුම් ක්‍රියාකරු, [...] සහ විනාශ කරන්නා විශේෂ සාමාජික කාර්යයන් වේ. [ සටහන : වැඩසටහන පැහැදිලිව ප්‍රකාශ නොකරන විට සමහර පන්ති වර්ග සඳහා මෙම සාමාජික ක්‍රියාකාරකම් ක්‍රියාත්මක කිරීම ව්‍යංගයෙන් ප්‍රකාශ කරනු ඇත. ඒවා භාවිතා කරන්නේ නම් ක්‍රියාත්මක කිරීම මඟින් ඒවා ව්‍යංගයෙන් අර්ථ දක්වනු ඇත. [...] අවසන් සටහන ] [n3126.pdf 12 වන කොටස]

පෙරනිමියෙන්, වස්තුවක් පිටපත් කිරීම යනු එහි සාමාජිකයන් පිටපත් කිරීම ය:

යූනියන් නොවන පංතිය සඳහා ව්‍යංගයෙන් නිර්වචනය කරන ලද පිටපත් සාදන්නා එහි උප විෂයයන්හි සාමාජික පිටපතක් සිදු කරයි. [n3126.pdf කොටස 12.8 §16]

X නොවන පන්තිය සඳහා ව්‍යංගයෙන් නිර්වචනය කරන ලද පිටපත් පැවරුම් ක්‍රියාකරු එහි උප විෂයයන්හි සාමාජික පිටපත් කිරීමේ පැවරුම සිදු කරයි. [n3126.pdf කොටස 12.8 §30]

ව්‍යංග අර්ථ දැක්වීම්

මේ සඳහා personපෙනුම සඳහා ව්‍යංගයෙන් අර්ථ දක්වා ඇති විශේෂ සාමාජික කාර්යයන් :

// 1. copy constructor
person(const person& that) : name(that.name), age(that.age)
{
}

// 2. copy assignment operator
person& operator=(const person& that)
{
    name = that.name;
    age = that.age;
    return *this;
}

// 3. destructor
~person()
{
}

Memberwise පිටපත් අපි මේ අවස්ථාවේ දී අවශ්ය දේ හරියටම: nameහා ageඅපි ස්වයං අන්තර්ගත ස්වාධීන ලබා නිසා, පිටපත් personවස්තුව. ව්‍යංගයෙන් නිර්වචනය කරන ලද විනාශ කරන්නා සෑම විටම හිස් ය. ඉදිකිරීම්කරුගේ සම්පත් අප විසින් අත්පත් කර නොගත් බැවින් මෙයද මෙම අවස්ථාවේ දී හොඳයි. සාමාජිකයාගේ විනාශ කරන්නන් ව්‍යංගයෙන් කැඳවනු personලැබේ.

විනාශ කරන්නාගේ ශරීරය ක්‍රියාත්මක කිරීමෙන් සහ ශරීරය තුළ වෙන් කර ඇති ඕනෑම ස්වයංක්‍රීය වස්තුවක් විනාශ කිරීමෙන් පසුව, X පන්තියේ විනාශ කරන්නෙකු X හි සෘජු [...] සාමාජිකයන් සඳහා විනාශ කරන්නන් අමතයි [n3126.pdf 12.4 §6]

සම්පත් කළමනාකරණය

ඉතින් අපි එම විශේෂ සාමාජික ක්‍රියාකාරකම් පැහැදිලිව ප්‍රකාශ කළ යුත්තේ කවදාද? අපේ පන්තිය සම්පතක් කළමනාකරණය කරන විට, එනම් පන්තියේ වස්තුවක් එම සම්පත සඳහා වගකිව යුතු විට. සාමාන්‍යයෙන් එයින් අදහස් වන්නේ සම්පත ඉදිකිරීම්කරු තුළ අත්පත් කර ගැනීම (හෝ ඉදිකිරීම්කරු වෙත ලබා දීම) සහ විනාශ කරන්නා තුළ මුදා හැරීමයි.

පූර්ව සම්මත C ++ වෙත අපි නැවත යමු. එබඳු දෙයක් නොතිබූ අතර std::string, ක්‍රමලේඛකයින් දර්ශකයන්ට ආදරය කළහ. මෙම personපන්ති මේ හා සමාන ය ඇති විය:

class person
{
    char* name;
    int age;

public:

    // the constructor acquires a resource:
    // in this case, dynamic memory obtained via new[]
    person(const char* the_name, int the_age)
    {
        name = new char[strlen(the_name) + 1];
        strcpy(name, the_name);
        age = the_age;
    }

    // the destructor must release this resource via delete[]
    ~person()
    {
        delete[] name;
    }
};

අදටත් මිනිසුන් මෙම ශෛලිය තුල පන්ති ලියන අතර කරදරයට පත්වේ: " මම පුද්ගලයෙකු දෛශිකයකට තල්ලු කළෙමි, දැන් මට පිස්සු මතක දෝෂ ඇතිවේ ! " පෙරනිමියෙන්, වස්තුවක් පිටපත් කිරීම යනු එහි සාමාජිකයන් පිටපත් කිරීම nameපමණක් නොව සාමාජිකයා පිටපත් කිරීම පමණක් බව මතක තබා ගන්න. පිටපත් අවධානය යොමුකළ, නෑ එය පෙන්නුම් චරිතය අරා! මෙය අප්රසන්න බලපෑම් කිහිපයක් ඇත:

  1. හරහා සිදුවන වෙනස්කම් aනිරීක්ෂණය කළ හැකිය b.
  2. bවිනාශ වූ පසු , a.nameඅන්තරාදායක දර්ශකයකි.
  3. aවිනාශ වුවහොත් , අන්තරාදායක දර්ශකය මකා දැමීමෙන් නිර්වචනය නොකළ හැසිරීමක් ලැබේ.
  4. පැවරුමට nameපෙර පෙන්වා දුන් දේ සැලකිල්ලට නොගන්නා හෙයින් , ඉක්මනින් හෝ පසුව ඔබට සෑම තැනකම මතක කාන්දු වේ.

පැහැදිලි අර්ථ දැක්වීම්

සාමාජික වශයෙන් පිටපත් කිරීම අපේක්ෂිත බලපෑමක් නොමැති බැවින්, අක්ෂර අරාවේ ගැඹුරු පිටපත් සෑදීම සඳහා අපි පිටපත් සාදන්නා සහ පිටපත් පැවරුම් ක්‍රියාකරු පැහැදිලිව අර්ථ දැක්විය යුතුය:

// 1. copy constructor
person(const person& that)
{
    name = new char[strlen(that.name) + 1];
    strcpy(name, that.name);
    age = that.age;
}

// 2. copy assignment operator
person& operator=(const person& that)
{
    if (this != &that)
    {
        delete[] name;
        // This is a dangerous point in the flow of execution!
        // We have temporarily invalidated the class invariants,
        // and the next statement might throw an exception,
        // leaving the object in an invalid state :(
        name = new char[strlen(that.name) + 1];
        strcpy(name, that.name);
        age = that.age;
    }
    return *this;
}

ආරම්භ කිරීම සහ පැවරුම අතර වෙනස සැලකිල්ලට ගන්න: nameමතක කාන්දු වීම වැළැක්වීම සඳහා පැවරීමට පෙර අපි පැරණි තත්වය ඉරා දැමිය යුතුය . එසේම, පෝරමයේ ස්වයං පැවරුමෙන් ආරක්ෂා විය යුතුය x = x. එම පරීක්ෂාවකින් තොරව, ප්‍රභවdelete[] name නූල අඩංගු අරාව මකා දමනු ඇත , මන්ද ඔබ ලියන විට දෙකම සහ එකම දර්ශකය අඩංගු වේ.x = xthis->namethat.name

ව්‍යතිරේක ආරක්ෂාව

අවාසනාවකට මෙන්, new char[...]මතක වෙහෙස නිසා ව්‍යතිරේකයක් විසි කළහොත් මෙම විසඳුම අසාර්ථක වනු ඇත . හැකි එක් විසඳුමක් නම් දේශීය විචල්‍යයක් හඳුන්වා දීම සහ ප්‍රකාශ නැවත සකස් කිරීම:

// 2. copy assignment operator
person& operator=(const person& that)
{
    char* local_name = new char[strlen(that.name) + 1];
    // If the above statement throws,
    // the object is still in the same state as before.
    // None of the following statements will throw an exception :)
    strcpy(local_name, that.name);
    delete[] name;
    name = local_name;
    age = that.age;
    return *this;
}

මෙය පැහැදිලි පරීක්ෂාවකින් තොරව ස්වයං පැවරුම ගැන සැලකිලිමත් වේ. මෙම ගැටළුවට ඊටත් වඩා ශක්තිමත් විසඳුමක් වන්නේ පිටපත් හා හුවමාරු මෝඩකමයි , නමුත් මම මෙහි ව්‍යතිරේක ආරක්ෂාව පිළිබඳ විස්තර වෙත නොයමි. පහත සඳහන් කරුණ ඉදිරිපත් කිරීම සඳහා මම ව්‍යතිරේක පමණක් සඳහන් කළෙමි: සම්පත් කළමනාකරණය කරන පන්ති ලිවීම දුෂ්කර ය.

පිටපත් කළ නොහැකි සම්පත්

සමහර සම්පත් ගොනු හැසිරවීම් හෝ මූටෙක්ස් වැනි පිටපත් කළ නොහැක. එවැනි අවස්ථාවක, privateඅර්ථ දැක්වීමක් ලබා නොදී පිටපත් සාදන්නා සහ පිටපත් පැවරුම් ක්‍රියාකරු ලෙස ප්‍රකාශ කරන්න :

private:

    person(const person& that);
    person& operator=(const person& that);

විකල්පයක් ලෙස, ඔබට boost::noncopyableඒවා මකාදැමූ බව උරුම කර ගැනීමට හෝ ප්‍රකාශ කිරීමට හැකිය (C ++ 11 සහ ඊට ඉහළින්):

person(const person& that) = delete;
person& operator=(const person& that) = delete;

තුන්දෙනෙකුගේ පාලනය

සමහර විට ඔබ සම්පතක් කළමනාකරණය කරන පන්තියක් ක්‍රියාත්මක කිරීමට අවශ්‍ය වේ. (තනි පන්තියක කිසි විටෙකත් බහු සම්පත් කළමනාකරණය නොකරන්න, මෙය වේදනාවට පමණක් හේතු වේ.) එවැනි අවස්ථාවකදී, තුනේ රීතිය මතක තබා ගන්න :

ඔබට විනාශ කරන්නා, පිටපත් සාදන්නා හෝ පිටපත් පැවරුම් ක්‍රියාකරු පැහැදිලිව ප්‍රකාශ කිරීමට අවශ්‍ය නම්, ඔබ ඔවුන් තිදෙනාම පැහැදිලිව ප්‍රකාශ කළ යුතුය.

(අවාසනාවකට මෙන්, මෙම "රීතිය" සී ++ ප්‍රමිතිය හෝ මා දන්නා කිසිදු සම්පාදකයෙකු විසින් බලාත්මක නොකෙරේ.)

පහේ පාලනය

C ++ 11 සිට, වස්තුවකට අමතර විශේෂ සාමාජික කාර්යයන් 2 ක් ඇත: චලන ඉදිකිරීම්කරු සහ චලනය පැවරීම. මෙම කාර්යයන් ක්‍රියාත්මක කිරීම සඳහා ප්‍රාන්ත පහක රීතිය.

අත්සන් සහිත උදාහරණයක්:

class person
{
    std::string name;
    int age;

public:
    person(const std::string& name, int age);        // Ctor
    person(const person &) = default;                // Copy Ctor
    person(person &&) noexcept = default;            // Move Ctor
    person& operator=(const person &) = default;     // Copy Assignment
    person& operator=(person &&) noexcept = default; // Move Assignment
    ~person() noexcept = default;                    // Dtor
};

බිංදුවේ නියමය

3/5 හි නියමය 0/3/5 හි රීතිය ලෙස ද හැඳින්වේ. රීතියේ ශුන්‍ය කොටසෙහි දැක්වෙන්නේ ඔබේ පන්තිය නිර්මාණය කිරීමේදී විශේෂ සාමාජික කාර්යයන් කිසිවක් ලිවීමට ඔබට අවසර නැති බවයි.

උපදෙස්

බොහෝ විට, ඔබ විසින්ම සම්පතක් කළමනාකරණය කර ගැනීමට අවශ්‍ය නොවේ, මන්ද දැනටමත් පවතින පන්තියක් std::stringඔබ වෙනුවෙන් එය කරයි. std::stringසාමාජිකයෙකු භාවිතා කර සරල කේතයක් සංසන්දනය කර දෝෂ සහිත විකල්පයක් සමඟ සංසන්දනය කරන්න . char*එවිට ඔබට ඒත්තු ගැන්විය යුතුය. ඔබ අමු දර්ශක සාමාජිකයන්ගෙන් stay ත්ව සිටින තාක් කල්, තුන්දෙනෙකුගේ රීතිය ඔබේ කේතය ගැන සැලකිලිමත් වීමට අපහසුය.


4
ෆ්‍රෙඩ්, (අ) ඔබ පිටපත් කළ හැකි කේතයේ නරක ලෙස ක්‍රියාවට නංවා ඇති පැවරුමක් නොකියන අතර එය වැරදියි කියා සටහනක් එකතු කර හොඳ තැනක වෙනත් තැනක බැලුවහොත් මට මගේ ඡන්දය ගැන හොඳ හැඟීමක් ඇති වේ; කේතයේ c & s භාවිතා කරන්න, නැතහොත් මෙම සියලු සාමාජිකයන් ක්‍රියාත්මක කිරීම මඟ හරින්න (B) ඔබ පළමු භාගය කෙටි කරනු ඇත, එය RoT සමඟ එතරම් සම්බන්ධයක් නැත; (ඇ) චලන අර්ථකථන හඳුන්වාදීම සහ RoT සඳහා එයින් අදහස් කරන්නේ කුමක්ද යන්න පිළිබඳව ඔබ සාකච්ඡා කරනු ඇත.
sbi

7
නමුත් පසුව තනතුර සී / ඩබ්ලිව් කළ යුතුය, මම සිතමි. මම කොන්දේසි බොහෝ දුරට නිවැරදිව තබා ගැනීමට කැමතියි (එනම් ඔබ " පිටපත් පැවරුම් ක්‍රියාකරු" යැයි පවසන අතර, පැවරුමට පිටපතක් අදහස් කළ නොහැකි පොදු උගුලට ඔබ තට්ටු නොකරන්න).
ජොහැන්නස් ෂෝබ් - litb

4
Ra ප්‍රසූන්: පිළිතුරෙන් අඩක් කැපීම සීඩබ්ලිව් නොවන පිළිතුරක “සාධාරණ සංස්කරණය” ලෙස පෙනෙනු ඇතැයි මම නොසිතමි.
sbi

69
ඔබ C ++ 11 සඳහා ඔබේ ලිපිය යාවත්කාලීන කරන්නේ නම් එය ඉතා හොඳ වේ (එනම් චලනය
සාදන්නා

5
usesolalito භාවිතයෙන් පසු ඔබ මුදා හැරිය යුතු ඕනෑම දෙයක්: සමගාමී අගුල්, ගොනු හැසිරවීම්, දත්ත සමුදා සම්බන්ධතා, ජාල සොකට්,
ගොඩවල්

510

මෙම ත්රී ආධිපත්යය, මූලික වශයෙන් කියමින්, C ++ සඳහා විශේෂයෙන් සැලකිලිමත් නීතියක් වේ

ඔබේ පන්තියට කිසිවක් අවශ්‍ය නම්

  • එය පිටපත් ඉදිකිරීමටත් ,
  • පැවරුම ක්රියාකරු ,
  • හෝ විනාශ කරන්නෙකු ,

පැහැදිලිව අර්ථ දක්වා ඇති විට, ඒ තුනම අවශ්‍ය වනු ඇත .

මේ සඳහා හේතු වන්නේ ඔවුන් තිදෙනාම සාමාන්‍යයෙන් සම්පතක් කළමනාකරණය කිරීම සඳහා භාවිතා කරන අතර ඔබේ පන්තිය සම්පතක් කළමනාකරණය කරන්නේ නම්, සාමාන්‍යයෙන් පිටපත් කිරීම මෙන්ම නිදහස් කිරීමද කළමනාකරණය කළ යුතුය.

ඔබේ පන්තිය කළමනාකරණය කරන සම්පත පිටපත් කිරීම සඳහා හොඳ අර්ථකථනයක් නොමැති නම් , පිටපත් සාදන්නා සහ පැවරුම් ක්‍රියාකරු ලෙස ප්‍රකාශ කිරීමෙන් ( නිර්වචනය නොකොට ) පිටපත් කිරීම තහනම් කිරීමට සලකා බලන්න private.

. තුන්වන නියමය ගැන.)


3
පිටපත් කිරීම වැළැක්වීම සඳහා තවත් විසඳුමක් නම්, පිටපත් කළ නොහැකි (වැනි boost::noncopyable) පන්තියකින් (පුද්ගලිකව) උරුම වීමයි. එය වඩාත් පැහැදිලි විය හැකිය. C ++ 0x සහ කාර්යයන් "මකාදැමීමේ" හැකියාව මෙහි උපකාරී වනු ඇතැයි මම සිතමි, නමුත් වාක්‍ය
ඛණ්ඩය

2
AtMatthieu: ඔව්, ඒකත් වැඩ කරනවා. නමුත් සාමාන්‍ය ලිබයේ noncopyableකොටසක් නොවේ නම්, එය වැඩි දියුණුවක් ලෙස මම නොසිතමි. (ඔහ්, ඔබට මකාදැමීමේ වාක්‍ය :)
ඛණ්ඩය

3
An ඩෑන්: මෙම පිළිතුර බලන්න . කෙසේ වෙතත්, මම ඇලුම් කිරීමට නිර්දේශ කරනවා Martinho ගේ ශුන්ය ආධිපත්යය . මට නම්, මෙය පසුගිය දශකය තුළ නිර්මාණය කරන ලද C ++ සඳහා ඉතා වැදගත් නීති රීති වලින් එකකි.
sbi

3
මාර්ටින්හෝගේ ශුන්‍ය නියමය දැන් වඩා හොඳය (පෙනෙන ඇඩ්වෙයාර් පවරා ගැනීමකින් තොරව) archive.org හි
නේතන් කිඩ්

161

විශාල තිදෙනාගේ නීතිය ඉහත දක්වා ඇති පරිදි වේ.

සරල ඉංග්‍රීසියෙන්, එය විසඳන ආකාරයේ ගැටලුවකට පහසු උදාහරණයක්:

පෙරනිමි නොවන විනාශ කරන්නා

ඔබ ඔබේ ඉදිකිරීම්කරු තුළ මතකය වෙන් කර ඇති අතර එය මකා දැමීමට ඔබට ඩිස්ට්‍රැක්ටරයක් ​​ලිවිය යුතුය. එසේ නොමැතිනම් ඔබ මතක කාන්දුවක් ඇති කරයි.

මෙය කාර්යයක් යැයි ඔබ සිතනු ඇත.

ගැටළුව වනුයේ, පිටපතක් ඔබේ වස්තුවෙන් සාදා ඇත්නම්, පිටපත මුල් වස්තුවට සමාන මතකයක් වෙත යොමු කරනු ඇත.

වරක්, මේවායින් එකක් එහි විනාශකයේ ඇති මතකය මකා දැමූ විට, අනෙකාට අවලංගු මතකය සඳහා දර්ශකයක් ඇත (මෙය ඩන්ග්ලිං පොයින්ටරයක් ​​ලෙස හැඳින්වේ) එය භාවිතා කිරීමට උත්සාහ කරන විට දේවල් කෙස් ගසනු ඇත.

එමනිසා, ඔබ පිටපත් සාදන්නෙකු ලියන අතර එමඟින් නව වස්තූන් විනාශ කිරීමට ඔවුන්ගේ මතක කොටස් වෙන් කරයි.

පැවරුම් ක්‍රියාකරු සහ පිටපත් සාදන්නා

ඔබේ පන්තියේ සාමාජික දර්ශකය වෙත ඔබේ ඉදිකිරීම්කරු තුළ මතකය වෙන් කර ඇත. ඔබ මෙම පන්තියේ වස්තුවක් පිටපත් කරන විට පෙරනිමි පැවරුම් ක්‍රියාකරු සහ පිටපත් සාදන්නා විසින් මෙම සාමාජික දර්ශකයේ වටිනාකම නව වස්තුවට පිටපත් කරනු ඇත.

මෙයින් අදහස් කරන්නේ නව වස්තුව සහ පැරණි වස්තුව එකම මතක කොටසකට යොමු වන බැවින් ඔබ එය එක් වස්තුවක වෙනස් කරන විට අනෙක් වස්තුව සඳහා ද එය වෙනස් වන බවයි. එක් වස්තුවක් මෙම මතකය මකා දැමුවහොත් අනෙකා එය භාවිතා කිරීමට උත්සාහ කරයි - eek.

මෙය විසඳීම සඳහා ඔබ පිටපත් සාදන්නාගේ සහ පැවරුම් ක්‍රියාකරුගේ ඔබේම පිටපතක් ලියයි. ඔබගේ අනුවාදයන් නව වස්තූන් සඳහා වෙනම මතකයක් වෙන් කර පළමු දර්ශකය යොමු කරන අගයන් හරහා එහි ලිපිනයට වඩා පිටපත් කරන්න.


4
එබැවින් අපි පිටපත් සාදන්නෙකු භාවිතා කරන්නේ නම් පිටපත සාදා ඇති නමුත් සම්පූර්ණයෙන්ම වෙනස් මතක ස්ථානයක වන අතර අපි පිටපත් සාදන්නා භාවිතා නොකරන්නේ නම් පිටපත් සාදනු ලබන නමුත් එය එකම මතක ස්ථානයට යොමු කරයි. ඔබ කියන්නට උත්සාහ කරන්නේ එයද? එබැවින් පිටපත් සාදන්නෙකු නොමැති පිටපතක් යනු නව දර්ශකයක් එහි ඇති නමුත් එකම මතක ස්ථානයට යොමු වීමයි. කෙසේ වෙතත් අපට පිටපත් සාදන්නා පැහැදිලිවම පරිශීලකයා විසින් නිර්වචනය කර ඇත්නම් අපට වෙනම දර්ශකයක් වෙනත් මතක ස්ථානයකට යොමු වන නමුත් දත්ත ඇත.
නොබිඳිය හැකි

4
කණගාටුයි, මම මීට අවුරුදු ගණනාවකට පෙර පිළිතුරු දුන් නමුත් මගේ පිළිතුර තවමත් මෙහි ඇති බවක් නොපෙනේ :-( මූලික වශයෙන්, ඔව් - ඔබට එය ලැබේ :-)
ස්ටෙෆාන්

1
පිටපත් පැවරුම් ක්‍රියාකරුට මූලධර්මය බලපාන්නේ කෙසේද? තුන්වන රීතියේ 3 වන කොටස සඳහන් කරන්නේ නම් මෙම පිළිතුර වඩාත් ප්‍රයෝජනවත් වනු ඇත.
ඩීබෙඩ්‍රෙන්කෝ

1
@DBedrenko, "ඔබ පිටපත් සාදන්නෙකු ලියන අතර එමඟින් නව වස්තූන් හට ඔවුන්ගේම මතක කොටස් වෙන් කරනු ලැබේ ..." මෙය පිටපත් පැවරුම් ක්‍රියාකරු වෙත විහිදෙන එකම මූලධර්මයයි. මම හිතන්නේ නැහැ මම ඒක පැහැදිලි කළා කියලා?
ස්ටෙෆාන්

2
BDBedrenko, මම තවත් තොරතුරු කිහිපයක් එකතු කර ඇත්තෙමි. එය වඩාත් පැහැදිලි වේද?
ස්ටෙෆාන්

44

මූලික වශයෙන් ඔබ සතුව ඩිස්ට්‍රැක්ටරයක් ​​තිබේ නම් (පෙරනිමි ඩිස්ට්‍රැක්ටර් නොවේ) එයින් අදහස් කරන්නේ ඔබ නිර්වචනය කළ පන්තියට යම් මතක වෙන් කිරීමක් ඇති බවයි. පන්තිය පිටත භාවිතා කරන්නේ යම් සේවාදායක කේතයක් හෝ ඔබ විසින් යැයි සිතමු.

    MyClass x(a, b);
    MyClass y(c, d);
    x = y; // This is a shallow copy if assignment operator is not provided

මයික්ලාස් හි ඇත්තේ ප්‍රාථමික ටයිප් කළ සාමාජිකයන් කිහිප දෙනෙකු පමණක් නම් පෙරනිමි පැවරුම් ක්‍රියාකරුවෙකු ක්‍රියා කරනු ඇත, නමුත් එහි සමහර දර්ශක සාමාජිකයන් සහ පැවරුම් ක්‍රියාකරුවන් නොමැති වස්තූන් තිබේ නම් ප්‍රති result ලය අනාවැකි කිව නොහැකි වනු ඇත. එබැවින් අපට කිව හැක්කේ පංතියක විනාශ කරන්නා තුළ මකා දැමීමට යමක් තිබේ නම්, අපට ගැඹුරු පිටපත් ක්‍රියාකරුවෙකු අවශ්‍ය විය හැකි අතර එයින් අදහස් කරන්නේ අපි පිටපත් සාදන්නෙකු සහ පැවරුම් ක්‍රියාකරුවෙකු සැපයිය යුතු බවයි.


36

වස්තුවක් පිටපත් කිරීමෙන් අදහස් කරන්නේ කුමක්ද? ඔබට වස්තු පිටපත් කළ හැකි ක්‍රම කිහිපයක් තිබේ - ඔබ බොහෝ විට සඳහන් කරන වර්ග 2 ගැන කතා කරමු - ගැඹුරු පිටපත සහ නොගැඹුරු පිටපත.

අප සිටින්නේ වස්තු-නැඹුරු භාෂාවක බැවින් (හෝ අවම වශයෙන් එසේ උපකල්පනය කරයි), අපි ඔබට මතක කොටසක් වෙන් කර ඇති බව කියමු. එය OO- භාෂාවක් බැවින්, අප විසින් වෙන් කරන ලද මතක කොටස් පහසුවෙන් යොමු කළ හැකිය, මන්ද ඒවා සාමාන්‍යයෙන් ප්‍රාථමික විචල්‍යයන් (ints, chars, bytes) හෝ අප විසින් නිර්වචනය කරන ලද පන්ති අපගේම වර්ග හා ප්‍රාථමික වලින් සාදා ඇත. එබැවින් අපි පහත පරිදි කාර් වර්ගයක් ඇති බව කියමු:

class Car //A very simple class just to demonstrate what these definitions mean.
//It's pseudocode C++/Javaish, I assume strings do not need to be allocated.
{
private String sPrintColor;
private String sModel;
private String sMake;

public changePaint(String newColor)
{
   this.sPrintColor = newColor;
}

public Car(String model, String make, String color) //Constructor
{
   this.sPrintColor = color;
   this.sModel = model;
   this.sMake = make;
}

public ~Car() //Destructor
{
//Because we did not create any custom types, we aren't adding more code.
//Anytime your object goes out of scope / program collects garbage / etc. this guy gets called + all other related destructors.
//Since we did not use anything but strings, we have nothing additional to handle.
//The assumption is being made that the 3 strings will be handled by string's destructor and that it is being called automatically--if this were not the case you would need to do it here.
}

public Car(const Car &other) // Copy Constructor
{
   this.sPrintColor = other.sPrintColor;
   this.sModel = other.sModel;
   this.sMake = other.sMake;
}
public Car &operator =(const Car &other) // Assignment Operator
{
   if(this != &other)
   {
      this.sPrintColor = other.sPrintColor;
      this.sModel = other.sModel;
      this.sMake = other.sMake;
   }
   return *this;
}

}

ගැඹුරු පිටපතක් යනු අප වස්තුවක් ප්‍රකාශයට පත් කර පසුව සම්පූර්ණයෙන්ම වෙනම පිටපතක් නිර්මාණය කරන්නේ නම් ... අපි අවසන් වන්නේ වස්තු 2 ක් සමඟ සම්පූර්ණයෙන්ම මතක කට්ටල 2 කිනි.

Car car1 = new Car("mustang", "ford", "red");
Car car2 = car1; //Call the copy constructor
car2.changePaint("green");
//car2 is now green but car1 is still red.

දැන් අපි අමුතු දෙයක් කරමු. කාර් 2 සෑදී ඇත්තේ වැරදි ලෙස හෝ හිතාමතාම කාර් 1 සෑදී ඇති සැබෑ මතකය බෙදා ගැනීමට යැයි කියමු. . වේ.

//Shallow copy example
//Assume we're in C++ because it's standard behavior is to shallow copy objects if you do not have a constructor written for an operation.
//Now let's assume I do not have any code for the assignment or copy operations like I do above...with those now gone, C++ will use the default.

 Car car1 = new Car("ford", "mustang", "red"); 
 Car car2 = car1; 
 car2.changePaint("green");//car1 is also now green 
 delete car2;/*I get rid of my car which is also really your car...I told C++ to resolve 
 the address of where car2 exists and delete the memory...which is also
 the memory associated with your car.*/
 car1.changePaint("red");/*program will likely crash because this area is
 no longer allocated to the program.*/

එබැවින් ඔබ ලියන භාෂාව කුමක් වුවත්, වස්තූන් පිටපත් කිරීමේදී ඔබ අදහස් කරන්නේ කුමක්ද යන්න පිළිබඳව ඉතා සැලකිලිමත් වන්න, මන්ද බොහෝ විට ඔබට ගැඹුරු පිටපතක් අවශ්‍ය වේ.

පිටපත් සාදන්නා සහ පිටපත් පැවරුම් ක්‍රියාකරු යනු කුමක්ද? මම දැනටමත් ඒවා ඉහත භාවිතා කර ඇත. ඔබ Car car2 = car1; අත්‍යාවශ්‍යයෙන්ම කේතයක් ටයිප් කරන විට පිටපත් සාදන්නා ලෙස හැඳින්වෙන්නේ ඔබ විචල්‍යයක් ප්‍රකාශ කර එය එක් පේළියකට පවරන්නේ නම්, එවිට පිටපත් සාදන්නා ලෙස හැඳින්වේ. පැවරුම් ක්‍රියාකරු යනු ඔබ සමාන ලකුණක් භාවිතා කරන විට සිදු වන දෙයයි car2 = car1;. car2එකම ප්‍රකාශයේ දැන්වීම ප්‍රකාශයට පත් නොකෙරේ. මෙම මෙහෙයුම් සඳහා ඔබ ලියන කේත කැබලි දෙක බොහෝ දුරට සමාන ය. ආරම්භක පිටපත / පැවරුම නීත්‍යානුකූල බව ඔබ සෑහීමකට පත්වූ පසු සෑම දෙයක්ම සැකසීමට සාමාන්‍ය මෝස්තර රටාවට තවත් කාර්යයක් ඇත - මා ලියා ඇති දිගු කේතය දෙස බැලුවහොත්, කාර්යයන් බොහෝ දුරට සමාන වේ.

ඒවා මා විසින්ම ප්‍රකාශ කිරීමට අවශ්‍ය වන්නේ කවදාද? ඔබ බෙදාහදා ගැනීමට හෝ යම් ආකාරයකින් නිෂ්පාදනය කිරීමට කේතයක් ලියන්නේ නැත්නම්, ඔබට ඒවා ප්‍රකාශ කිරීමට අවශ්‍ය වන්නේ ඔබට අවශ්‍ය විටදී පමණි. ඔබ එය 'අහම්බෙන්' භාවිතා කිරීමට තෝරාගෙන එකක් සෑදුවේ නැත්නම් ඔබේ වැඩසටහන් භාෂාව කරන්නේ කුමක්ද යන්න පිළිබඳව ඔබ දැනුවත් විය යුතුය - එනම් ඔබට සම්පාදක පෙරනිමිය ලැබේ. උදාහරණයක් ලෙස මම පිටපත් සාදන්නන් භාවිතා කරන්නේ කලාතුරකිනි, නමුත් පැවරුම් ක්‍රියාකරු අභිබවා යාම ඉතා සුලභ ය. එකතු කිරීම, අඩු කිරීම යනාදියෙහි තේරුම ද ඉක්මවා යා හැකි බව ඔබ දැන සිටියාද?

මගේ වස්තූන් පිටපත් කිරීම වළක්වා ගන්නේ කෙසේද? පුද්ගලික ශ්‍රිතයක් සමඟ ඔබේ වස්තුව සඳහා මතකය වෙන් කිරීමට ඔබට අවසර දී ඇති සියලු ක්‍රම ඉක්මවා යන්න සාධාරණ ආරම්භයකි. මිනිසුන් ඒවා පිටපත් කිරීම ඔබට ඇත්තටම අවශ්‍ය නැතිනම්, ඔබට එය ප්‍රසිද්ධ කළ හැකි අතර ව්‍යතිරේකයක් විසි කිරීමෙන් සහ වස්තුව පිටපත් නොකිරීමෙන් ක්‍රමලේඛකයා දැනුවත් කළ හැකිය.


5
ප්‍රශ්නය C ++ ලෙස ටැග් කරන ලදි. මෙම ව්‍යාජ කේත ප්‍රදර්ශනය මඟින් මනාව නිර්වචනය කර ඇති “තුන්වන රීතිය” ගැන කිසිවක් පැහැදිලි කර ගත නොහැකි අතර, ව්‍යාකූලත්වය නරකම ලෙස පැතිරෙයි.
sehe

26

ඒවා මා විසින්ම ප්‍රකාශ කිරීමට අවශ්‍ය වන්නේ කවදාද?

තුන්වන රීතියේ සඳහන් වන්නේ ඔබ කිසිවක් ප්‍රකාශ කරන්නේ නම් a

  1. පිටපත් සාදන්නා
  2. පිටපත් පැවරුම් ක්‍රියාකරු
  3. විනාශ කරන්නා

එවිට ඔබ මේ තුනම ප්‍රකාශ කළ යුතුය. පිටපත් මෙහෙයුමක අර්ථය භාර ගැනීමේ අවශ්‍යතාවය සෑම විටම පාහේ කිසියම් ආකාරයක සම්පත් කළමනාකරණයක් සිදු කරන පන්තියෙන් පැන නැගී ඇති බව නිරීක්‍ෂණයෙන් එය වර්ධනය විය.

  • එක් පිටපත් මෙහෙයුමකදී සම්පත් කළමණාකරනය සිදු කරනු ලැබුවද අනෙක් පිටපත් මෙහෙයුමේදී සිදු කිරීමට අවශ්‍ය විය හැකිය

  • පංති විනාශ කරන්නා සම්පත් කළමනාකරණයට ද සහභාගී වේ (සාමාන්‍යයෙන් එය මුදා හැරීම). කළමනාකරණය කළ යුතු සම්භාව්‍ය සම්පත මතකය වන අතර මතකය කළමනාකරණය කරන සියලුම සම්මත පුස්තකාල පන්ති (උදා: ගතික මතක කළමනාකරණය කරන STL බහාලුම්) සියල්ලම “විශාල තුන” ප්‍රකාශයට පත් කරයි: පිටපත් මෙහෙයුම් සහ විනාශ කරන්නා යන දෙකම.

තුන්වන රීතියේ ප්‍රතිවිපාකය නම්, පරිශීලකයා විසින් ප්‍රකාශයට පත් කරන ලද ඩිස්ට්‍රැක්ටරයක් ​​තිබීම පෙන්නුම් කරන්නේ සරල සාමාජික නැණවත් පිටපතක් පන්තියේ පිටපත් කිරීමේ මෙහෙයුම් සඳහා සුදුසු නොවන බවයි. එයින් ඇඟවෙන්නේ, පංතියක් විනාශකාරකයක් ප්‍රකාශ කරන්නේ නම්, පිටපත් මෙහෙයුම් ස්වයංක්‍රීයව ජනනය නොකළ යුතු අතර, ඔවුන් නිවැරදි දේ නොකරන නිසා ය. සී ++ 98 සම්මත කරන විට, මෙම තර්කනයේ වැදගත්කම සම්පූර්ණයෙන් අගය නොකෙරුණි, එබැවින් සී ++ 98 හි, පරිශීලක ප්‍රකාශිත ඩිස්ට්‍රැක්ටරයක පැවැත්ම පිටපත් මෙහෙයුම් උත්පාදනය කිරීමට සම්පාදකයින්ගේ කැමැත්ත කෙරෙහි කිසිදු බලපෑමක් ඇති කළේ නැත. සී ++ 11 හි එය දිගටම පවතී, නමුත් පිටපත් මෙහෙයුම් උත්පාදනය වන කොන්දේසි සීමා කිරීම නිසා බොහෝ උරුම කේතය බිඳ වැටෙනු ඇත.

මගේ වස්තූන් පිටපත් කිරීම වළක්වා ගන්නේ කෙසේද?

පිටපත් සාදන්නා සහ පිටපත් පැවරුම් ක්‍රියාකරු පුද්ගලික ප්‍රවේශ පිරිවිතරයක් ලෙස ප්‍රකාශ කරන්න.

class MemoryBlock
{
public:

//code here

private:
MemoryBlock(const MemoryBlock& other)
{
   cout<<"copy constructor"<<endl;
}

// Copy assignment operator.
MemoryBlock& operator=(const MemoryBlock& other)
{
 return *this;
}
};

int main()
{
   MemoryBlock a;
   MemoryBlock b(a);
}

C ++ 11 සිට ඔබට පිටපත් සාදන්නා සහ පැවරුම් ක්‍රියාකරු මකා දැමූ බව ප්‍රකාශ කළ හැකිය

class MemoryBlock
{
public:
MemoryBlock(const MemoryBlock& other) = delete

// Copy assignment operator.
MemoryBlock& operator=(const MemoryBlock& other) =delete
};


int main()
{
   MemoryBlock a;
   MemoryBlock b(a);
}

16

දැනට පවතින බොහෝ පිළිතුරු දැනටමත් පිටපත් සාදන්නා, පැවරුම් ක්‍රියාකරු සහ විනාශ කරන්නා ස්පර්ශ කරයි. කෙසේ වෙතත්, පශ්චාත් C ++ 11 හි, චලන අර්ථකථනය හඳුන්වාදීම මෙය 3 න් ඔබ්බට පුළුල් කළ හැකිය.

මෑතකදී මයිකල් ක්ලයිස් මෙම මාතෘකාවට ස්පර්ශ වන කතාවක් ඉදිරිපත් කළේය: http://channel9.msdn.com/events/CPP/C-PP-Con-2014/The-Canonical-Class


10

C ++ හි තුනේ රීතිය සැලසුමේ මූලික මූලධර්මයක් වන අතර පහත සඳහන් සාමාජික ශ්‍රිතයක පැහැදිලි අර්ථ දැක්වීමක් තිබේ නම් ක්‍රමලේඛකයා අනෙක් සාමාජිකයන් දෙදෙනාගේ ක්‍රියාකාරිත්වය එකට අර්ථ දැක්විය යුතුය. පහත සඳහන් සාමාජික කාර්යයන් තුන අත්‍යවශ්‍ය වේ: විනාශ කරන්නා, පිටපත් සාදන්නා, පිටපත් පැවරුම් ක්‍රියාකරු.

C ++ හි පිටපත් සාදන්නා විශේෂ ඉදිකිරීම්කරුවෙකි. එය නව වස්තුවක් තැනීමට භාවිතා කරයි, එය පවතින වස්තුවක පිටපතකට සමාන නව වස්තුවකි.

පිටපත් පැවරුම් ක්‍රියාකරු යනු විශේෂ පැවරුම් ක්‍රියාකරුවෙකු වන අතර එය සාමාන්‍යයෙන් පවතින වස්තුවක් එකම වර්ගයේ වස්තුවකට නියම කිරීමට භාවිතා කරයි.

ඉක්මන් උදාහරණ ඇත:

// default constructor
My_Class a;

// copy constructor
My_Class b(a);

// copy constructor
My_Class c = a;

// copy assignment operator
b = a;

7
හායි, ඔබේ පිළිතුරට අලුත් කිසිවක් එකතු නොවේ. අනෙක් අය මෙම විෂය වඩාත් ගැඹුරින් හා වඩාත් නිවැරදිව ආවරණය කරයි - ඔබේ පිළිතුර දළ වශයෙන් සහ සමහර ස්ථානවල ඇත්ත වශයෙන්ම වැරදියි (එනම් මෙහි "අනිවාර්යයෙන්ම" නැත; එය "බොහෝ විට කළ යුතුය"). දැනටමත් තරයේ පිළිතුරු දී ඇති ප්‍රශ්න වලට මෙවැනි පිළිතුරක් පළ කරන විට එය ඇත්තෙන්ම වටින්නේ නැත. ඔබට එකතු කිරීමට අලුත් දේවල් නොමැති නම්.
මතෙ

1
එසේම, ඉක්මන් උදාහරණ හතරක් ඇත , ඒවා කෙසේ හෝ තුන්දෙනාගේ රීතිය ගැන කතා කරන තිදෙනාගෙන් දෙදෙනෙකුට සම්බන්ධ වේ . ඕනෑවට වඩා ව්‍යාකූල.
anatolyg
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.