नाम से सदस्य सरणी में तत्वों तक पहुंचने के लिए प्रॉक्सी क्लास का उपयोग करने का एक तरीका है। यह बहुत सी ++ है, और इसमें सिंटैक्टिक वरीयता को छोड़कर रेफरी-रिटर्निंग एक्सेसर फ़ंक्शंस का कोई लाभ नहीं है। यह ->
ऑपरेटर को सदस्यों के रूप में तत्वों का उपयोग करने के लिए अधिभारित करता है , इसलिए स्वीकार्य होने के लिए, दोनों को एक्सेसर्स ( d.a() = 5;
) के सिंटैक्स को नापसंद करने की आवश्यकता होती है , साथ ही ->
गैर-पॉइंटर ऑब्जेक्ट के साथ उपयोग करने को सहन करना पड़ता है । मुझे उम्मीद है कि यह पाठकों को कोड से परिचित न होने के लिए भ्रमित कर सकता है, इसलिए यह कुछ साफ-सुथरी चाल से अधिक हो सकता है जो आप उत्पादन में डालना चाहते हैं।
Data
इस कोड में struct भी अपने अंदर पहुँच अनुक्रमित तत्वों के लिए, सबस्क्रिप्ट ऑपरेटर के लिए भार के शामिल ar
, सरणी सदस्य के साथ-साथ begin
औरend
काम करता है, यात्रा के लिए। इसके अलावा, इन सभी को गैर-कास्ट और कास्ट संस्करणों के साथ अतिभारित किया जाता है, जो मुझे पूर्णता के लिए शामिल करने की आवश्यकता महसूस हुई।
जब Data
's ->
नाम से एक तत्व तक पहुंचना है (इस तरह: प्रयोग किया जाता है my_data->b = 5;
), एक Proxy
वस्तु दिया जाता है। फिर, क्योंकि यह Proxy
प्रतिद्वंद्विता पॉइंटर नहीं है, इसका अपना ->
ऑपरेटर ऑटो-चेन-कॉल है, जो अपने आप में एक पॉइंटर लौटाता है। इस तरह, Proxy
ऑब्जेक्ट को त्वरित किया जाता है और प्रारंभिक अभिव्यक्ति के मूल्यांकन के दौरान वैध रहता है।
किसी Proxy
ऑब्जेक्ट का निर्देश उसके 3 संदर्भ सदस्यों को पॉप्युलेट करता है a
, b
और c
कंस्ट्रक्टर में पारित एक पॉइंटर के अनुसार, जिसे एक बफर को इंगित करने के लिए माना जाता है जिसमें कम से कम 3 मान होते हैं, जिसका प्रकार टेम्पलेट पैरामीटर के रूप में दिया जाता है T
। इसलिए नामित संदर्भों का उपयोग करने के बजाय जो Data
वर्ग के सदस्य हैं , यह एक्सेस के बिंदु पर संदर्भों को पॉप्युलेट करके मेमोरी को बचाता है (लेकिन दुर्भाग्य से, ऑपरेटर का उपयोग करके ->
और नहीं .
)।
यह जांचने के लिए कि कंपाइलर के ऑप्टिमाइज़र ने उपयोग के द्वारा शुरू किए गए सभी अप्रत्यक्ष को समाप्त कर दिया है Proxy
, नीचे दिए गए कोड में 2% शामिल हैं main()
। #if 1
संस्करण का उपयोग करता ->
है और []
ऑपरेटर, और #if 0
संस्करण प्रदर्शन प्रक्रियाओं के बराबर सेट, लेकिन सीधे तक पहुँचने केवल द्वाराData::ar
।
Nci()
समारोह सरणी तत्वों आरंभ, जो सिर्फ प्रत्येक में सीधे निरंतर मूल्यों को प्लग से अनुकूलक से बचाता है के लिए क्रम पूर्णांक मूल्यों उत्पन्न करता हैstd::cout
<<
कॉल।
6.2 gcc के लिए, -O3 का उपयोग करते हुए, दोनों main()
विधानसभा के दोनों संस्करण एक ही असेंबली उत्पन्न करते हैं ( तुलना करने वाले पहले #if 1
और #if 0
पहले टॉगल main()
करें): https://godbolt.org/g/QqRWZb
#include <iostream>
#include <ctime>
template <typename T>
class Proxy {
public:
T &a, &b, &c;
Proxy(T* par) : a(par[0]), b(par[1]), c(par[2]) {}
Proxy* operator -> () { return this; }
};
struct Data {
int ar[3];
template <typename I> int& operator [] (I idx) { return ar[idx]; }
template <typename I> const int& operator [] (I idx) const { return ar[idx]; }
Proxy<int> operator -> () { return Proxy<int>(ar); }
Proxy<const int> operator -> () const { return Proxy<const int>(ar); }
int* begin() { return ar; }
const int* begin() const { return ar; }
int* end() { return ar + sizeof(ar)/sizeof(int); }
const int* end() const { return ar + sizeof(ar)/sizeof(int); }
};
// Nci returns an unpredictible int
inline int Nci() {
static auto t = std::time(nullptr) / 100 * 100;
return static_cast<int>(t++ % 1000);
}
#if 1
int main() {
Data d = {Nci(), Nci(), Nci()};
for(auto v : d) { std::cout << v << ' '; }
std::cout << "\n";
std::cout << d->b << "\n";
d->b = -5;
std::cout << d[1] << "\n";
std::cout << "\n";
const Data cd = {Nci(), Nci(), Nci()};
for(auto v : cd) { std::cout << v << ' '; }
std::cout << "\n";
std::cout << cd->c << "\n";
//cd->c = -5; // error: assignment of read-only location
std::cout << cd[2] << "\n";
}
#else
int main() {
Data d = {Nci(), Nci(), Nci()};
for(auto v : d.ar) { std::cout << v << ' '; }
std::cout << "\n";
std::cout << d.ar[1] << "\n";
d->b = -5;
std::cout << d.ar[1] << "\n";
std::cout << "\n";
const Data cd = {Nci(), Nci(), Nci()};
for(auto v : cd.ar) { std::cout << v << ' '; }
std::cout << "\n";
std::cout << cd.ar[2] << "\n";
//cd.ar[2] = -5;
std::cout << cd.ar[2] << "\n";
}
#endif