2011-01-26 34 views
12

स्थैतिक चर के प्रारंभ के संबंध में बहुत से प्रश्न पढ़ने के बाद भी मुझे यकीन नहीं है कि यह नामस्थान स्तर पर const चर पर कैसे लागू होता है।हेडर फ़ाइल में स्थिर चर और स्थिर प्रारंभिक फ़ियास्को

static const std::string path1 = "/xyz/abc"; 
static const std::string path2 = "/etc"; 

मैं क्या static कीवर्ड पढ़ा है के अनुसार आवश्यक नहीं है, यहां तक ​​कि यहां पदावनत:

मैं एक हैडर फ़ाइल config.h निर्माण स्क्रिप्ट द्वारा उत्पन्न में निम्न कोड की तरह है।

मेरा प्रश्न: क्या उपरोक्त कोड स्थिर प्रारंभिक फ़ियास्को से प्रवण है?

मैं एक हैडर फ़ाइल myclass.h में निम्नलिखित है:

class MyClass 
{ 
public: 
    MyClass(const std::string& str) : m_str(str) {} 
    std::string Get() const { return m_str; } 

private: 
    std::string m_str; 
} 

const MyClass myclass1("test"); 

इस स्थिर प्रारंभ के साथ कोई समस्या पैदा होगी?

यदि मुझे सही समझा जाता है, const आंतरिक संबंध वाले चर के कारण दोनों मामलों में कोई समस्या नहीं होनी चाहिए?

संपादित करें: (dribeas जवाब के कारण)

शायद मैं उल्लेख करना चाहिए कि मैं की तरह उपयोग के मामलों में दिलचस्पी है:

main.cpp में:

#include <config.h> 
#include <myclass.h> 

std::string anotherString(path1 + myclass1.Get()); 

int main() 
{ 
    ... 
} 

एक और सवाल यह उपयोग के संबंध में मामला: क्या इस मामले में संकलक path2 को अनुकूलित करेगा?

उत्तर

9

मैंने सी ++ 03 मानक दस्तावेज़ से आवश्यक जानकारी प्राप्त करने का प्रयास किया।

const static घोषणाओं के बारे में::

अनुभाग के लिए 3.5.3 वस्तुओं नाम स्थान स्तर पर परिभाषित अनुसार और घोषित const डिफ़ॉल्ट रूप से आंतरिक संबंध है यहाँ मैं क्या मिला है। static आंतरिक लिंकेज रखने के लिए नामस्थान स्तर ऑब्जेक्ट भी घोषित करता है इसलिए ऑब्जेक्ट static const घोषित करने की कोई आवश्यकता नहीं है।

के बाद से चर एक हेडर फाइल में परिभाषित कर रहे हैं वे हमेशा उनका इस्तेमाल किसी अन्य स्थिर वस्तुओं से पहले परिभाषित कर रहे हैं:

इसके अलावा अनुबंध D.2

The use of the static keyword is deprecated when declaring objects in namespace scope (see 3.3.5).

स्थिर प्रारंभ असफलता के बारे में के अनुसार

खंड 3.6.2.1 से:

Objects with static storage duration defined in namespace scope in the same translation unit and dynamically initialized shall be initialized in the order in which their definition appears in the translation unit.

उत्तर 1:गुजर एक स्थिर वस्तु constuctor को चर ठीक होना चाहिए इसका मतलब यह है।

उत्तर 2: हालांकि एक समस्या हो सकता है चर एक स्थिर वस्तु के एक गैर इनलाइन निर्माता द्वारा दर्शाया जाता है यदि:

न तो खंड 3.6.2.1 और न ही 3.6.2.3 में यह किस क्रम में निर्दिष्ट किया जाता है विभिन्न संकलन इकाइयों में स्थिर वस्तुओं को प्रारंभ किया गया है यदि गतिशील प्रारंभ main के पहले विवरण से पहले किया जाता है।

निम्नलिखित पर विचार करें:

// consts.h 
#include <string> 

const std::string string1 = "ham"; 
const std::string string2 = "cheese"; 

// myclass.h 
#include <string> 

class MyClass 
{ 
public: 
    MyClass(); 
    MyClass(std::string str); 
    std::string Get() { return memberString; } 
private: 
    std::string memberString; 
} 

// myclass.cpp 
#include "consts.h" 
#include "myclass.h" 

MyClass::MyClass() : memberString(string1) {} 

MyClass::MyClass(std::string str) : memberString(str) {} 

// main.cpp 
#include <iostream> 
#include "consts.h" 
#include "myclass.h" 

MyClass myObject1; 
MyClass myObject2(string2); 

using namespace std; 

int main() 
{ 
    cout << myObject1.Get(); // might not print "ham" 
    cout << myObject2.Get(); // will always print "cheese" 
} 

myclass.cpp के बाद से const चर की अपनी एक प्रतिलिपि है, इन जब कहा जाता है आरंभ नहीं किया जा सकता है।

तो हाँ, const चर हेडर फाइल में परिभाषित किया गया एक तरीका है कि स्थिर प्रारंभ असफलता की संभावना है में इस्तेमाल किया जा सकता

जहां तक ​​मैं देख सकता हूँ यह केवल स्थिर प्रारंभ की जरूरत नहीं चर पर लागू होता है:

सी ++ 03 मानक, खंड 3.6.2.1 से:

Objects of POD types (3.9) with static storage duration initialized with constant expressions (5.19) shall be initialized before any dynamic initialization takes place.

12

आपकी पहली परिभाषा path1 प्रत्येक संकलन इकाई में config.h शामिल है। इससे बचने के लिए, हेडर फ़ाइलों में चर परिभाषित न करें। आम तौर पर आप extern के रूप में शीर्षक में चर घोषित चाहते हैं:

extern const std::string path1; 
extern const MyClass myclass1; 

और उन्हें एक कार्यान्वयन फ़ाइल में परिभाषित करता है, उदा config.cpp:

const std::string path1 = "/xyz/abc"; 
const MyClass myclass1("test"); 

कभी कभी तुम एक निरंतर परिवर्तनशील है कि केवल एक कार्यान्वयन फ़ाइल से प्रयोग करने योग्य है की जरूरत है। फिर आप उस चर को फ़ाइल स्कोप पर static के रूप में घोषित कर सकते हैं।

static const std::string path1 = "/xyz/abc"; 

static अब और बहिष्कृत नहीं किया गया है। static और extern कभी-कभी निहित होते हैं, लेकिन मैं हमेशा कहां और कैसे भूल जाता हूं, इसलिए मैं आमतौर पर उन्हें सभी नामस्थान-स्तर चर के लिए स्पष्ट रूप से निर्दिष्ट करता हूं।

+1

यह सच नहीं है कि 'static' केवल कार्यान्वयन फाइलों में इस्तेमाल किया जा सकता। –

+0

बेशक, सी ++ में कार्यान्वयन फ़ाइल की कोई अवधारणा नहीं है, मैं – Philipp

+2

शब्द बदलने की कोशिश करूंगा, मुझे लगता है कि आप जिस वाक्यांश को खोज रहे हैं वह कार्यान्वयन फ़ाइल के बजाय "अनुवाद इकाई" है। मानकों को हेडर में घोषित किया जाना चाहिए और अधिकांश एक अनुवाद इकाई में परिभाषित किया जाना चाहिए। इस मामले में, चूंकि वे स्थिर हैं और आंतरिक संबंध को निहित करते हैं, इसलिए आपको लिंक समय पर एक गुणा परिभाषित प्रतीक त्रुटि नहीं मिलती है, लेकिन आपके पास प्रत्येक शीर्षलेख इकाई में परिभाषित एक ही प्रतीक है जिसमें यह हेडर शामिल है। चूंकि उनके पास आंतरिक संबंध है, इसलिए वे लिंकिंग नहीं तोड़ते हैं, लेकिन संकलक डुप्लिकेट को खत्म नहीं कर सकता है। मैंने एक बार हेडर से तारों की परिभाषाओं को हटाकर एक निष्पादन योग्य से 8 एमबी को मुंडा दिया। – legalize

8

स्थिर प्रारंभिक फ़ियास्को के रूप में क्या संदर्भित किया जाता है एक समस्या है जब एक नेमस्पेस स्तर चर भिन्न नामस्थान स्तर चर निर्दिष्ट करने वाले मान पर निर्भर करता है जो पहले शुरू किया जा सकता है या नहीं। आपके दो उदाहरणों में ऐसी कोई निर्भरता नहीं है और कोई समस्या नहीं होनी चाहिए।

यह, दूसरे हाथ पर, त्रुटि के प्रकार का खतरा है:

// header.h 
extern const std::string foo; 

// constant.cpp 
const std::string foo("foo"); 

// main.cpp 
#include "header.h" 
const std::string foobar(foo+"bar"); 
int main() { 
    std::cout << foobar << std::endl; 
} 

कोई गारंटी नहीं कि foofoobar से पहले प्रारंभ हो जाएगा, भले ही दोनों लगातार हो रहा है। इसका मतलब है कि प्रोग्राम व्यवहार अपरिभाषित है और यह "foobar", "bar" या मरने के लिए अच्छी तरह प्रिंट कर सकता है।

+0

मैंने मूल उपयोग में अपना उपयोग केस अपडेट किया। यह वही परिदृश्य है जिसे मैं जानना चाहता हूं। –

+0

मैं उस पर टिप्पणी की हिम्मत नहीं करूंगा। मेरा पहला विचार यह है कि यह ठीक होना चाहिए (निरंतर अनुवाद इकाई के लिए स्थानीय है, और दूसरे स्थिरांक से पहले परिभाषित किया गया है), लेकिन यदि संभव हो तो मैं उस निर्माण से बचूंगा। मुझे सबसे सरल तरीका पता होना चाहिए कि वैश्विक वैर के बजाय आंतरिक रूप से एक स्थैतिक चर के साथ एक फ़ंक्शन का उपयोग किया जाएगा: 'इनलाइन myclass और global_object() {myclass उदाहरण; वापसी उदाहरण; } 'भाषा गारंटी देता है कि' आवृत्ति 'पूरी तरह से फ़ंक्शन के पहले कॉल में प्रारंभ की जाएगी, इसलिए 'std :: स्ट्रिंग अन्य (global_object()।());' निश्चित रूप से काम करेगा ... –

+2

किसी भी दर पर, मैं * वास्तव में * इसे पूरी तरह से टालने की कोशिश करता हूं और उनके प्रारंभिकरण के साथ नामस्थान स्तर चर को खत्म करता हूं। नामस्थान स्तर चर का प्रारंभिक मामूली नहीं है, यह दो पासों में होता है, जहां सभी * ग्लोबल्स * जो स्थिरांक से तत्काल होते हैं, उनके मान पहले प्राप्त होते हैं, और फिर एक दूसरे पास में जो गैर-स्थिर पर निर्भर होता है, उसके अनुसार प्रारंभ किया जाएगा परिभाषा का क्रम (उसी अनुवाद इकाई के भीतर), एक अपरिभाषित क्रम में जब एक से अधिक अनुवाद इकाई किसी प्रोग्राम में जुड़ी होती है। –

2

स्टेटिक प्रारंभिक फ़ियास्को स्थिर चर को संदर्भित करता है जो पर एक-दूसरे पर निर्भर करता है। कुछ static const चर को परिभाषित करना समस्या का स्रोत नहीं होगा।

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