2016-12-01 10 views
7

मैं निम्नलिखित कोड आदेश g++ -std=c++11 t.cpp का उपयोग कर संकलन:क्या सी ++ 11 बल बिना शर्त के चलता है?

#include <vector> 
#include <cstring> //memcpy() 
class s 
{ 
    char *p; 
    size_t size; 
public: 
    s(){ 
     size=10; 
     p=new char[size]; 
    } 
    s(const s &other){ 
     size=other.size; 
     p=new char[size]; 
     memcpy(p,other.p,other.size); 
    } 
    ~s(){ delete [] p; } 
}; 

int main() 
{ 
    std::vector<s> ss; 
    ss.push_back(s()); 
} 

यह gdb लॉग है:

Breakpoint 1, main() at t.cpp:23 
23   ss.push_back(s()); 
s::s (this=0x7fffffffe370) at t.cpp:9 
9    size=10; 
10    p=new char[size]; 
11   } 
std::vector<s, std::allocator<s> >::push_back(s&&) (this=0x7fffffffe350, 
    __x=<unknown type in /tmp/a.out, CU 0x0, DIE 0x20d0>) 
    at /usr/include/c++/4.9/bits/stl_vector.h:932 
932  { emplace_back(std::move(__x)); } 
std::move<s&> (__t=...) at /usr/include/c++/4.9/bits/move.h:102 
102  { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); } 
std::vector<s, std::allocator<s> >::emplace_back<s>(s&&) (this=0x7fffffffe350) 
    at /usr/include/c++/4.9/bits/vector.tcc:94 
94  if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) 
101  _M_emplace_back_aux(std::forward<_Args>(__args)...); 
102  } 
s::~s (this=0x7fffffffe370, __in_chrg=<optimized out>) at t.cpp:17 
17   ~s(){ delete [] p; } 
std::vector<s, std::allocator<s> >::~vector (this=0x7fffffffe350, __in_chrg=<optimized out>) 
    at /usr/include/c++/4.9/bits/stl_vector.h:425 

लॉग से, मैं निम्नलिखित प्रभाव में हूं:

  1. जीसीसी पर ध्यान नहीं देता प्रतिलिपि निर्माता s(const s &other)
  2. जीसीसी स्वचालित रूप से class s के लिए एक move निर्माता बनाता है और फिर std::vector.push_back() कॉल move निर्माता।

    :

    This article राज्यों

    इस प्रकार, यदि क्लास सी की परिभाषा को स्पष्ट रूप से एक कदम असाइनमेंट ऑपरेटर की घोषणा नहीं करता है, एक परोक्ष घोषित रूप में चूक ही अगर निम्न स्थितियों में मुलाकात कर रहे हैं के सभी हो जाएगा

    मेरे यहाँ सवाल class s जाहिरा तौर पर, एक उपयोगकर्ता के घोषित नाशक ~s() है जिसका अर्थ है class s आगे शर्त को पूरा नहीं करता है और इस तरह जीसीसी std::vector.push_back() पर move लागू नहीं करना चाहिए। जीसीसी कैसे व्यवहार करता है?

  3. नाशक ~s() दो बार कहा जाता है: पहले तुरंत अस्थायी s() के बाद ss.push_back(s());को तर्क के रूप में पारित कर दिया गया है और ले जाया गया है, और दूसरा std::vector<s> का नाशक कहा जाता है के बाद।

  4. क्योंकि यह कोड rule of three से मेल नहीं खाता है, इसलिए std::vector<s> के विनाशक को क्रैश होने पर यह दुर्घटनाग्रस्त हो जाता है। ऑब्जेक्ट s में p द्वारा इंगित सामग्री पहले ~s() द्वारा पहले ही हटा दी गई है। इसलिए, std::vector<s>~s() को नष्ट करने वाले विनाशक को double free or corruption जैसे त्रुटि से क्रैश होना चाहिए।

हालांकि, मेरे आश्चर्य के लिए, किसी भी तरह से यह प्रोग्राम सामान्य रूप से चलता है और समाप्त हो जाता है।

प्रश्न 1: प्रोग्राम क्यों क्रैश नहीं होता है? क्या मैं बस भाग्यशाली हूं?

प्रश्न 2: gdb लॉग के अनुसार, इसका मतलब यह है कि पहले सी ++ 11 बैठक rule of three लेकिन rule of five बैठक नहीं, तो इस उदाहरण की तरह के लिए बनाया गया कोड, बहुत जब वे सेल्सियस के लिए संकलित किया गया है दुर्घटना की संभावना है ++ 11 निष्पादन योग्य?

संपादित:

यह सवाल इस तरह के gdb संदेशों के मेरी अशुद्ध अर्थ के कारण उठाया गया था:

std::vector<s, std::allocator<s> >::push_back(s&&) 
emplace_back(std::move(__x)); 
std::vector<s, std::allocator<s> >::emplace_back<s>(s&&) 

जो मुझे नेतृत्व कि जीसीसी एक चाल निर्माता बनाता है सोचने के लिए।मैंने अभी तक इन विशेषज्ञों को बताया है - s(const s &other) में ब्रेक पॉइंट सेट करना, और ध्यान दिया कि कार्यक्रम वहां रुक गया है। यह खोज मेरे सभी सवालों को अमान्य कर देती है।

जैसा कि यहां हर विशेषज्ञ ने सुझाव दिया है, तथ्यों हैं: 1. जीसीसी कोई भी चालक कन्स्ट्रक्टर नहीं बनाता है। 2. मौजूदा प्रतिलिपि निर्माता को बुलाया जाता है।

बड़ी मदद के लिए सभी को धन्यवाद!

+3

कॉपी कन्स्ट्रक्टर में ब्रेकपॉइंट डालने का प्रयास करें। क्या कार्यक्रम उस ब्रेकपॉइंट पर रुकता है? –

+4

यह 'पुश_बैक' नए तत्व को आरंभ करने के लिए आंतरिक रूप से 'std :: move' नामक फ़ंक्शन को कॉल करता है, लेकिन यह प्रारंभिक प्रतिलिपि बनानेवाला का उपयोग करता है (क्योंकि कोई चालक कन्स्ट्रक्टर नहीं है और कॉपी कन्स्ट्रक्टर सबसे अच्छा मिलान है)। कोई चालक कन्स्ट्रक्टर उत्पन्न या बुलाया नहीं जाता है। – cpplearner

+0

@ Somprogrammerdude मैंने अभी किया था। हां, कार्यक्रम कॉपी कन्स्ट्रक्टर में बंद हो जाता है। –

उत्तर

3

हममम, इस जाँच:

#include <vector> 
#include <cstring> //memcpy() 
#include <iostream> 
class s 
{ 
    char *p; 
    size_t size; 
public: 
    s(){ 
     std::cout<<this<<"\tdefault constructor\n"; 
     size=10; 
     p=new char[size]; 
    } 
    s(const s &other){ 
     std::cout<<this<<"\tcopy constructor\n"; 
     size=other.size; 
     p=new char[size]; 
     memcpy(p,other.p,other.size); 
    } 
    ~s(){ 
     std::cout<<this<<"\tdestructor\n"; 
     delete [] p; 
    } 
}; 

int main() 
{ 
    std::vector<s> ss; 
    ss.push_back(s()); 
} 

मेरे लिए, मैं विलुप्त हो रही हूँ 2 अलग वस्तु:
0x7fffc879aa50 डिफ़ॉल्ट निर्माता
0x1668c40 प्रतिलिपि निर्माता
0x7fffc879aa50 नाशक
0x1668c40 नाशक

प्रश्न 1: कार्यक्रम क्यों दुर्घटनाग्रस्त नहीं होता है? क्या मैं बस भाग्यशाली हूं?

कोई दोगुना मुक्त नहीं है।

साथ संकलित: file2.out
जी ++ 4.7.3

+0

संदेश '0x1668c40 कॉपी कन्स्ट्रक्टर' सफलतापूर्वक मेरी चिंताओं को हटा देता है हालांकि मुझे लगता है कि दो 'विनाशक' संदेश यह साबित नहीं करते हैं कि दो 'पी' द्वारा इंगित दो सामग्री अलग-अलग हैं। –

3

तो एक प्रति निर्माता स्पष्ट रूप से घोषित किया गया है जी ++ -O3 --std = C++ 11 file2.cpp -ओ (आपके मामले में) कोई चालक कन्स्ट्रक्टर या असाइनमेंट कन्स्ट्रक्टर स्वचालित रूप से संकलक द्वारा उत्पन्न नहीं होता है।

कॉपी कन्स्ट्रक्टर सबसे अच्छा उम्मीदवार है और अस्थायी जेनरेट तत्व (दोनों डिफ़ॉल्ट और कॉपी कन्स्ट्रक्टर को बुलाया जाता है) की प्रतिलिपि बनाने के लिए उपयोग किया जाता है।

यह आपको strong exception safety guarantee भी देता है।

+0

आप पूर्ण अधिकार हैं। आपका बहुत बहुत धन्यवाद! –

8

जीसीसी कॉपी कन्स्ट्रक्टर एस (कॉन्स एस & अन्य) को अनदेखा करता है।

यह एक प्रति-अनुकूलन अनुकूलन के रूप में ऐसा कर सकता है।

जीसीसी स्वचालित रूप से कक्षाओं के लिए एक चालक कन्स्ट्रक्टर बनाता है और फिर std :: vector.push_back() कॉल जो कन्स्ट्रक्टर को स्थानांतरित करता है।

नहीं। एक चालक कन्स्ट्रक्टर उत्पन्न नहीं होता है।

मेरे यहां सवाल यह है कि वर्ग जाहिरा तौर पर है एक उपयोगकर्ता के घोषित नाशक ~ s (है) है, जिसका अर्थ है वर्ग रों आगे हालत

सही पूरा नहीं करता। कक्षा पहली शर्त (उपयोगकर्ता घोषित प्रतिलिपि निर्माता) को पूरा नहीं करती है।

जीसीसी कैसे व्यवहार करता है?

जीसीसी ऐसा व्यवहार करना प्रतीत होता है जैसा इसे करना चाहिए।कोई कदम निर्माण या असाइनमेंट शामिल नहीं है।

नाशक ~ रों() दो बार

gdb लॉग जिसे आप दिखाना में कहा जाता है, मैं सिर्फ देख s::~s का एक उदाहरण बुलाया जा रहा है।

प्रश्न 1: प्रोग्राम क्यों क्रैश नहीं होता है? क्या मैं बस भाग्यशाली हूं?

मैं आपको दुर्भाग्यपूर्ण मानता हूं। ऐसा लगता है कि push_back ने कॉपी असाइनमेंट ऑपरेटर का उपयोग नहीं किया था, इसलिए डबल फ्री के लिए शर्तें नहीं हुईं।

प्रश्न 2: gdb लॉग के अनुसार, इसका मतलब यह है कि तीन में से पहले सी ++ 11 बैठक शासन के लिए बनाया गया कोड लेकिन पांच में से नियम को पूरा नहीं, इस उदाहरण की तरह ...

यह उदाहरण तीन के नियम को पूरा नहीं करता है, इसलिए ऐसा लगता है कि आप जो मांग रहे हैं उसका उदाहरण नहीं है।

सी ++ 11 निष्पादन योग्यों के संकलित होने पर क्रैश होने की संभावना बहुत अधिक है?

नहीं। जब तक कोड तीन के नियमों का पालन करता है, तो वस्तुओं की प्रतिलिपि बनाना सुरक्षित है। वस्तु को चलने योग्य बनाने के लिए पांच के नियम के बाद केवल आवश्यक है (प्रतिलिपि से बचने के लिए)।

+0

धन्यवाद! वास्तव में यह उदाहरण कोड 'तीन के नियम' को पूरा नहीं करता है। कोड को आसानी से पढ़ने के लिए जितना संभव हो सके उतना छोटा रखने के लिए 'प्रतिलिपि असाइनमेंट ऑपरेटर' छोड़ा गया और आशा प्राप्त करने का बेहतर मौका मिलने की उम्मीद थी। जाहिर है मैंने इसे बहुत छोटा बना दिया। –

संबंधित मुद्दे