pimpl मुहावरा के साथ स्मार्ट संकेत का उपयोग करते समय के रूप में,Pimpl: अजीब अधूरा प्रकार मुद्दा
struct Foo
{
private:
struct Impl;
boost::scoped_ptr<Impl> pImpl;
};
में स्पष्ट समस्या यह है कि Foo::Impl
बिंदु पर अधूरा है वह जगह है जहाँ Foo
का विनाशक उत्पन्न होता है।
संकलनकर्ता आमतौर पर एक चेतावनी वहाँ फेंकना, और boost::checked_delete
, जो बूस्ट स्मार्ट संकेत द्वारा आंतरिक रूप से प्रयोग किया जाता है, स्थिर दावा वर्ग Foo::Impl
पूरा हो गया है कि और एक त्रुटि से चलाता है अगर यह मामला नहीं है।
ऊपर के उदाहरण को संकलित करने के लिए, एक इसलिए
struct Foo
{
~Foo();
private:
struct Impl;
boost::scoped_ptr<Impl> pImpl;
};
लिखने और कार्यान्वयन फ़ाइल, जहां Foo::Impl
पूरा हो गया है में एक खाली Foo::~Foo
को लागू करना चाहिए। यह नंगे पॉइंटर्स पर स्मार्ट पॉइंटर्स का एक लाभ है, क्योंकि हम विनाशक को लागू करने में विफल नहीं हो सकते हैं।
अभी तक, बहुत अच्छा है। लेकिन मैं एक अजीब व्यवहार जब मैं एक ऐसी ही Bar
कक्षा में एक टेम्पलेट निर्माता को पेश करने की कोशिश में आए (पूर्ण कोड, यह अपने आप कोशिश करें):
// File Bar.h
#ifndef BAR_H
#define BAR_H 1
#include <vector>
#include <boost/scoped_ptr.hpp>
struct Bar
{
template <typename I>
Bar(I begin, I end);
~Bar();
private:
struct Impl;
boost::scoped_ptr<Impl> pImpl;
void buildImpl(std::vector<double>&);
};
template <typename I>
Bar::Bar(I begin, I end)
{
std::vector<double> tmp(begin, end);
this->buildImpl(tmp);
}
#endif // BAR_H
// File Bar.cpp
#include "Bar.h"
struct Bar::Impl
{
std::vector<double> v;
};
void Bar::buildImpl(std::vector<double>& v)
{
pImpl.reset(new Impl);
pImpl->v.swap(v);
}
Bar::~Bar() {}
// File Foo.h
#ifndef FOO_H
#define FOO_H 1
#include <boost/scoped_ptr.hpp>
struct Foo
{
Foo();
~Foo();
private:
struct Impl;
boost::scoped_ptr<Impl> pImpl;
};
#endif // FOO_H
// File Foo.cpp
#include "Foo.h"
struct Foo::Impl
{};
Foo::Foo() : pImpl(new Impl)
{}
Foo::~Foo() {}
// File Main.cpp
#include "Foo.h"
#include "Bar.h"
int main()
{
std::vector<double> v(42);
Foo f;
Bar b(v.begin(), v.end());
}
जब दृश्य स्टूडियो 2005 SP1 के साथ इस उदाहरण संकलन, मैं एक मिल Foo
साथ Bar
नहीं बल्कि साथ त्रुटि:
1>Compiling...
1>main.cpp
1>c:\users\boost_1_45_0\boost\checked_delete.hpp(32) : error C2027: use of undefined type 'Bar::Impl'
1> c:\users\visual studio 2005\projects\checkeddeletetest\checkeddeletetest\bar.h(15) : see declaration of 'Bar::Impl'
1> c:\users\boost_1_45_0\boost\smart_ptr\scoped_ptr.hpp(80) : see reference to function template instantiation 'void boost::checked_delete<T>(T *)' being compiled
1> with
1> [
1> T=Bar::Impl
1> ]
1> c:\users\boost_1_45_0\boost\smart_ptr\scoped_ptr.hpp(76) : while compiling class template member function 'boost::scoped_ptr<T>::~scoped_ptr(void)'
1> with
1> [
1> T=Bar::Impl
1> ]
1> c:\users\visual studio 2005\projects\checkeddeletetest\checkeddeletetest\bar.h(16) : see reference to class template instantiation 'boost::scoped_ptr<T>' being compiled
1> with
1> [
1> T=Bar::Impl
1> ]
1>c:\users\boost_1_45_0\boost\checked_delete.hpp(32) : error C2118: negative subscript
1>c:\users\boost_1_45_0\boost\checked_delete.hpp(34) : warning C4150: deletion of pointer to incomplete type 'Bar::Impl'; no destructor called
1> c:\users\visual studio 2005\projects\checkeddeletetest\checkeddeletetest\bar.h(15) : see declaration of 'Bar::Impl'
मैं जितनी जल्दी घर पहुंचने पर के रूप में हाल ही में एक जीसीसी के साथ इस कोशिश करेंगे।
मुझे समझ नहीं आता कि क्या हो रहा है: (। यानी Bar.cpp
में) बिंदु जहां नाशक परिभाषित किया गया है पर, Bar::Impl
की एक परिभाषा उपलब्ध है, तो कोई समस्या नहीं होनी चाहिए। यह Foo
के साथ क्यों काम करता है और Bar
के साथ नहीं?
मुझे यहां क्या याद आ रही है?
ठीक है, मैं देखता हूं कि मैं क्या खो रहा था। प्रश्न आज एक वास्तविक दुनिया के मुद्दे का एक खिलौना सरलीकरण है जो मेरे साथ हुआ था। इस्तेमाल किया जाने वाला वास्तविक पॉइंटर क्लास 'boost :: shared_ptr' है, इस प्रकार मेरे पास यहां एक नंगे पॉइंटर नहीं हो सकता है। मैं कस्टम डिलीटर का उपयोग करके जांच करूंगा। धन्यवाद। –
मैं उपयोगी से कम से असहमत हूं। ** क्योंकि 'scoped_ptr' के उपयोग के कारण ** संकलक द्वारा समस्या को हाइलाइट किया गया है यदि आप विनाशक को लिखना भूल जाते हैं, तो विनाशक शरीर भी बेहद सरल (खाली ...) है। दूसरी ओर, कच्चे सूचक का उपयोग करके आपको अधिसूचित नहीं किया जाएगा और कॉल करना होगा। साथ ही, 'shared_ptr' का उपयोग करके, एम्बेडेड डिलीटर के लिए धन्यवाद, वास्तव में आपको एक विनाशक लिखने के बोझ से राहत देता है। –
@ मैथियू: यह स्वाद का विषय है, मैं सरल और शक्तिशाली कोड पसंद करता हूं, इसमें कोई अनावश्यक शामिल नहीं है। –