2011-02-01 17 views
22

में रैल्यू पर बहुत सारी प्रतियां उत्पन्न करते हैं। मैं लिनक्स & विंडोज दोनों के लिए एक ऐप लिख रहा हूं, और ध्यान दिया कि जीसीसी बिल्ड कॉपी कन्स्ट्रक्टर को बहुत बेकार कॉल का उत्पादन कर रहा है।मानक लाइब्रेरी कंटेनर जीसीसी

struct A 
{ 
    A()    { std::cout << "default" << std::endl; } 
    A(A&& rvalue)  { std::cout << "move" << std::endl; } 
    A(const A& lvalue) { std::cout << "copy" << std::endl; } 
    A& operator =(A a) { std::cout << "assign" << std::endl; return *this; } 
}; 

BOOST_AUTO_TEST_CASE(test_copy_semantics) 
{ 
    std::vector<A> vec_a(3); 
} 

इस परीक्षा सिर्फ 3 तत्वों का एक वेक्टर बनाता है:

यहाँ इस व्यवहार का निर्माण करने के लिए एक उदाहरण कोड है। मैं 3 डिफ़ॉल्ट कन्स्ट्रक्टर कॉल और 0 प्रतियों की अपेक्षा करता हूं क्योंकि A लाइवल्स नहीं हैं।

विजुअल C++ 2010 में, उत्पादन होता है:

default 
move 
default 
move 
default 
move 

जीसीसी 4.4.0 (MinGW) में, (-O2 -std = C++ 0x), उत्पादन होता है:

default 
copy 
copy 
copy 

क्या चल रहा है और मैं इसे कैसे ठीक कर सकता हूं? वास्तविक वर्ग के लिए प्रतियां महंगा हैं, डिफ़ॉल्ट निर्माण और चाल सस्ते हैं।

+1

क्या आपने '' हेडर देखा है? कन्स्ट्रक्टर क्या कर रहा है? जीसीसी व्यवहार सी ++ 03 spec के साथ संगत है, जहां एक ऑब्जेक्ट डिफॉल्ट बनाया गया है, फिर एन बार कॉपी किया गया है। यह संभव है कि मानक लाइब्रेरी का आपका संस्करण C++ 0x में जोड़े गए नए कन्स्ट्रक्टर का समर्थन नहीं करता है, जो डिफ़ॉल्ट रूप से एन तत्वों का निर्माण करता है। –

+1

क्योंकि उदाहरण सी ++ 0x भाषा सुविधाओं का उपयोग करता है, मुझे लगता है कि यह C++ 0x spec के बारे में एक प्रश्न है, सी ++ 03 spec नहीं। –

+1

जीसीसी 4.5 – tstenner

उत्तर

18

दोनों कार्यान्वयन (दृश्य सी ++ 2010 और जीसीसी 4.4.0) त्रुटि में हैं। सही उत्पादन होता है:

default 
default 
default 

यह/4 में 23.3.5.1 [vector.cons] निर्दिष्ट किया जाता है:

आवश्यक है: टी DefaultConstructible होगा।

कार्यान्वयन को यह मानने की अनुमति नहीं है कि ए या तो MoveConstructible है और न ही प्रतिलिपि बनाने योग्य है।

+5

+1, इसके वीएस पक्ष पर अच्छी पकड़। –

+0

आप सही हैं, मेरा अगला सवाल यह होगा कि वीसी चालन क्यों बना रहा है। क्या कुछ और हो सकता है? कोई विचार अगर स्टर्लपोर्ट या ईए के कार्यान्वयन अधिक अनुरूप हैं? – Inverse

+0

यह std :: lib: http://libcxx.llvm.org/ सही उत्तर प्राप्त करता है, लेकिन विंडोज़ को पोर्ट नहीं किया गया है। विंडोज़ को पोर्ट करने में दिलचस्पी रखने वाली पार्टियां हैं और इसमें कोई संदेह नहीं है कि मदद का उपयोग करें। –

1

तो यह प्रयास करें:

std::vector<A> vec_a; 
vec_a.reserve(3); 
for (size_t i = 0; i < 3; ++i) 
    vec_a.push_back(A()); 

आपको क्या करने की कोशिश कर रहे हैं निर्माण के बजाय प्रत्येक मान के लिए निर्माण + चाल का उपयोग करने के लिए और फिर कॉपी/कॉपी/कॉपी आरंभीकरण प्रक्रिया के लिए मजबूर है। ये सिर्फ अलग दर्शन हैं; पुस्तकालय लेखकों को संभवतः यह नहीं पता था कि किसी दिए गए प्रकार के लिए सबसे अच्छा कौन सा होगा।

+4

यह विभिन्न दर्शन से अधिक है। सी ++ 0 एक्स ड्राफ्ट सही व्यवहार निर्दिष्ट करता है। –

+1

+1, प्रस्तावित कोड वास्तव में एक कामकाज है। –

6

ऐसा लगता है कि समस्या यह है कि आपके पास जी ++ का संस्करण सी ++ 0x पूरी तरह अनुपालन लाइब्रेरी नहीं है।

// C++ 03 
explicit vector(size_type n, const T& value = T(), 
const Allocator& = Allocator()); 
कि समारोह हस्ताक्षर और अपने कॉल के साथ

, एक अस्थायी बनाया जाता है, तो निरंतर संदर्भ और प्रतियां से बंधे: विशेष रूप से, सी ++ 03 में, std :: वेक्टर के आकार निर्माता निम्नलिखित हस्ताक्षर हैं यह तत्वों में से प्रत्येक के लिए बनाया गया है।

C++ 0x वहाँ विभिन्न निर्माता ये हैं, जबकि:

// C++0x 
explicit vector(size_type n); 
vector(size_type n, const T& value, const Allocator& = Allocator()); 

इस मामले में, अपने कॉल पहले हस्ताक्षर से मेल खाएगा, और तत्वों डिफ़ॉल्ट कंटेनर से अधिक नए प्लेसमेंट के साथ निर्माण किया जाना चाहिए (के रूप में @ हॉवर्ड हिन्नेंट सही ढंग से अपने answer में बताते हैं कि संकलक को चालक कन्स्ट्रक्टर को बिल्कुल कॉल नहीं करना चाहिए)।

आप कोशिश करते हैं और अगर जी के नवीनतम संस्करण ++ एक अद्यतन किया है मानक पुस्तकालय की जांच कर सकते हैं, या आप मैन्युअल रूप से समस्या के तत्व जोड़कर काम कर सकते हैं:

std::vector<A> v; 
v.reserve(3);  // avoid multiple relocations 
while (v.size() < 3) v.push_back(A()); 
1

आप के लिए विशेष (सस्ते) मामले में जोड़ सकते हैं "इस" ऑब्जेक्ट में डिफ़ॉल्ट निर्मित ऑब्जेक्ट की प्रतिलिपि बनाते समय ctor algorithm की प्रतिलिपि बनाएँ। यह सिर्फ एक कामकाज है, हालांकि, व्यवहार काफी अजीब है। दोनों कंपाइलर्स (पुस्तकालय) ढेर पर एक अस्थायी वस्तु बनाते हैं, तो जीसीसी इस अस्थायी को लक्ष्य 3 बार प्रतिलिपि बनाता है; एमएसवीसी अस्थायी वस्तु को 3 बार (!) (ढेर पर भी) दोबारा शुरू करता है और लक्ष्य के लिए 3 गुना चलता है। मुझे समझ में नहीं आता कि वे वस्तुओं को सीधे जगह क्यों नहीं बनाते हैं।

0

मुझे लगता है कि सभी 3 प्रकार C++ 0x ड्राफ्ट का उल्लंघन नहीं करते हैं। यह निम्न की आवश्यकता है: 1. Constructs n मूल्य प्रारंभ तत्वों के साथ एक वेक्टर 2. टी एन

में 3. रैखिक DefaultConstructible होगा

सभी 3 वेरिएंट 1 को संतुष्ट, डिफ़ॉल्ट + प्रतिलिपि, डिफ़ॉल्ट + कदम के रूप में के बराबर हैं डिफ़ॉल्ट सभी 3 प्रकार संतुष्ट 3 सभी 3 प्रकार संतुष्ट 2: वे डिफ़ॉल्ट कॉन्स्ट्राक्टेबल प्रकारों के लिए काम करते हैं। चलने योग्य प्रकारों के लिए विशिष्ट एल्गोरिदम का उपयोग किया जा सकता है। विभिन्न क्षमताओं वाले प्रकारों के लिए एल्गोरिदम के विभिन्न संस्करणों का उपयोग करने के लिए एसटीएल में यह एक सामान्य प्रथा है।

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