আপনার নিজের এসটিএল কনটেইনার লিখছেন


120

কীভাবে কোনও নতুন ধারক লিখতে হবে যা কোনও ধারকগুলির মতো আচরণ করবে সে সম্পর্কে কী নির্দেশিকা STLরয়েছে?


7
বিদ্যমান স্ট্যান্ডার্ড পাত্রে বাস্তবায়ন দেখুন এবং সেগুলি বোঝার চেষ্টা করুন - ফাংশন, রিটার্নের ধরণ, অপারেটর ওভারলোড, নেস্টেড ধরণ, মেমরি পরিচালনা এবং সমস্ত।
নওয়াজ

আমি সাধারণত এমএসডিএন বা স্ট্যান্ডার্ড থেকে যা করছি তার ধারণার নিকটতম যে কোনও ধারকটির সদস্য ফাংশন প্রোটোটাইপগুলি অনুলিপি করে শুরু করি। ( সিপিএলস্প্লস.কম এর সি ++ ১১ টি ফাংশন নেই, এবং www.sgi.com মেলে না)
মাকিং হাঁস

@ মুভিং হাঁস: আপনি কি মনে করেন এমএসডিএন সাগির চেয়ে মানের কাছাকাছি?
দানি

3
এটা অবশ্যই। এমএসডিএন বর্তমান - এসজিআই প্রি-স্ট্যান্ডার্ড
পিপি

9
সেরা অনলাইন রেফারেন্স (রিং সম্পূর্ণতা, সঠিকতা এবং বিশেষত ব্যবহারযোগ্যতা) হ'ল cppreferences.com by এটি গ্রন্থাগার থেকে আলাদা করে এক টন ভাষার বৈশিষ্ট্যও ব্যাখ্যা করে। এবং এটি একটি উইকি, সুতরাং এটিতে cplusplus.com এর চেয়ে কম ত্রুটি থাকা উচিত।
রুবেনভবি

উত্তর:


209

A 23.2.1 \ 4 থেকে একসাথে পাইসড সিউডো-ধারকটি এখানে রইল Note iterator_category কোনো একটি হওয়া আবশ্যক std::input_iterator_tag, std::output_iterator_tag, std::forward_iterator_tag, std::bidirectional_iterator_tag, std::random_access_iterator_tag। এছাড়াও নোট করুন যে নীচেরটি প্রযুক্তিগতভাবে প্রয়োজনের তুলনায় আরও কঠোর, তবে এটি ধারণা। দ্রষ্টব্য যে "স্ট্যান্ডার্ড" ফাংশনগুলির সিংহভাগটি প্রযুক্তিগতভাবে বৈকল্পিক, যা পুনরাবৃত্তিকারীদের দুর্দান্ততার কারণে।

template <class T, class A = std::allocator<T> >
class X {
public:
    typedef A allocator_type;
    typedef typename A::value_type value_type; 
    typedef typename A::reference reference;
    typedef typename A::const_reference const_reference;
    typedef typename A::difference_type difference_type;
    typedef typename A::size_type size_type;

    class iterator { 
    public:
        typedef typename A::difference_type difference_type;
        typedef typename A::value_type value_type;
        typedef typename A::reference reference;
        typedef typename A::pointer pointer;
        typedef std::random_access_iterator_tag iterator_category; //or another tag

        iterator();
        iterator(const iterator&);
        ~iterator();

        iterator& operator=(const iterator&);
        bool operator==(const iterator&) const;
        bool operator!=(const iterator&) const;
        bool operator<(const iterator&) const; //optional
        bool operator>(const iterator&) const; //optional
        bool operator<=(const iterator&) const; //optional
        bool operator>=(const iterator&) const; //optional

        iterator& operator++();
        iterator operator++(int); //optional
        iterator& operator--(); //optional
        iterator operator--(int); //optional
        iterator& operator+=(size_type); //optional
        iterator operator+(size_type) const; //optional
        friend iterator operator+(size_type, const iterator&); //optional
        iterator& operator-=(size_type); //optional            
        iterator operator-(size_type) const; //optional
        difference_type operator-(iterator) const; //optional

        reference operator*() const;
        pointer operator->() const;
        reference operator[](size_type) const; //optional
    };
    class const_iterator {
    public:
        typedef typename A::difference_type difference_type;
        typedef typename A::value_type value_type;
        typedef typename const A::reference reference;
        typedef typename const A::pointer pointer;
        typedef std::random_access_iterator_tag iterator_category; //or another tag

        const_iterator ();
        const_iterator (const const_iterator&);
        const_iterator (const iterator&);
        ~const_iterator();

        const_iterator& operator=(const const_iterator&);
        bool operator==(const const_iterator&) const;
        bool operator!=(const const_iterator&) const;
        bool operator<(const const_iterator&) const; //optional
        bool operator>(const const_iterator&) const; //optional
        bool operator<=(const const_iterator&) const; //optional
        bool operator>=(const const_iterator&) const; //optional

        const_iterator& operator++();
        const_iterator operator++(int); //optional
        const_iterator& operator--(); //optional
        const_iterator operator--(int); //optional
        const_iterator& operator+=(size_type); //optional
        const_iterator operator+(size_type) const; //optional
        friend const_iterator operator+(size_type, const const_iterator&); //optional
        const_iterator& operator-=(size_type); //optional            
        const_iterator operator-(size_type) const; //optional
        difference_type operator-(const_iterator) const; //optional

        reference operator*() const;
        pointer operator->() const;
        reference operator[](size_type) const; //optional
    };

    typedef std::reverse_iterator<iterator> reverse_iterator; //optional
    typedef std::reverse_iterator<const_iterator> const_reverse_iterator; //optional

    X();
    X(const X&);
    ~X();

    X& operator=(const X&);
    bool operator==(const X&) const;
    bool operator!=(const X&) const;
    bool operator<(const X&) const; //optional
    bool operator>(const X&) const; //optional
    bool operator<=(const X&) const; //optional
    bool operator>=(const X&) const; //optional

    iterator begin();
    const_iterator begin() const;
    const_iterator cbegin() const;
    iterator end();
    const_iterator end() const;
    const_iterator cend() const;
    reverse_iterator rbegin(); //optional
    const_reverse_iterator rbegin() const; //optional
    const_reverse_iterator crbegin() const; //optional
    reverse_iterator rend(); //optional
    const_reverse_iterator rend() const; //optional
    const_reverse_iterator crend() const; //optional

    reference front(); //optional
    const_reference front() const; //optional
    reference back(); //optional
    const_reference back() const; //optional
    template<class ...Args>
    void emplace_front(Args&&...); //optional
    template<class ...Args>
    void emplace_back(Args&&...); //optional
    void push_front(const T&); //optional
    void push_front(T&&); //optional
    void push_back(const T&); //optional
    void push_back(T&&); //optional
    void pop_front(); //optional
    void pop_back(); //optional
    reference operator[](size_type); //optional
    const_reference operator[](size_type) const; //optional
    reference at(size_type); //optional
    const_reference at(size_type) const; //optional

    template<class ...Args>
    iterator emplace(const_iterator, Args&&...); //optional
    iterator insert(const_iterator, const T&); //optional
    iterator insert(const_iterator, T&&); //optional
    iterator insert(const_iterator, size_type, T&); //optional
    template<class iter>
    iterator insert(const_iterator, iter, iter); //optional
    iterator insert(const_iterator, std::initializer_list<T>); //optional
    iterator erase(const_iterator); //optional
    iterator erase(const_iterator, const_iterator); //optional
    void clear(); //optional
    template<class iter>
    void assign(iter, iter); //optional
    void assign(std::initializer_list<T>); //optional
    void assign(size_type, const T&); //optional

    void swap(X&);
    size_type size() const;
    size_type max_size() const;
    bool empty() const;

    A get_allocator() const; //optional
};
template <class T, class A = std::allocator<T> >
void swap(X<T,A>&, X<T,A>&); //optional

এছাড়াও, যখনই আমি একটি ধারক তৈরি করি, আমি কম-বেশি ক্লাসের সাথে এই জাতীয় পরীক্ষা করি:

#include <cassert>
struct verify;
class tester {
    friend verify;
    static int livecount;
    const tester* self;
public:
    tester() :self(this) {++livecount;}
    tester(const tester&) :self(this) {++livecount;}
    ~tester() {assert(self==this);--livecount;}
    tester& operator=(const tester& b) {
        assert(self==this && b.self == &b);
        return *this;
    }
    void cfunction() const {assert(self==this);}
    void mfunction() {assert(self==this);}
};
int tester::livecount=0;
struct verify {
    ~verify() {assert(tester::livecount==0);}
}verifier;

testerবস্তুগুলির পাত্রে তৈরি করুন এবং function()আপনার ধারকটি পরীক্ষা করার সাথে সাথে প্রত্যেককে কল করুন । কোনও গ্লোবাল করবেন নাtester অবজেক্ট । যদি আপনার ধারকটি কোথাও প্রতারণা করে তবে এই testerশ্রেণীটি হবে assertএবং আপনি জানতে পারবেন যে আপনি দুর্ঘটনাক্রমে অন্য কোথাও প্রতারণা করেছেন।


1
এটা মজার. আপনার পরীক্ষক কিভাবে কাজ করে? বেশ কয়েকটি পার্স ত্রুটি রয়েছে, যা তুচ্ছ (নিখোঁজ ';') তবে কীভাবে তা যাচাই করে যে ডেস্ট্রাক্টর কীভাবে কাজ করে তা নিশ্চিত নয়। ওহ, আপনি বোঝানো assert(tester::livecount == 0);। মুমম্ম, এখনও এই পরীক্ষক কাঠামোটি কীভাবে কাজ করে তা নিশ্চিত। আপনি একটি উদাহরণ দিতে পারেন?
অ্যাড্রিয়ান

2
পরীক্ষকটির একটি একক ননস্ট্যাটিক সদস্য থাকে যা নিজেই এটির জন্য একটি পয়েন্টার, এবং ডেস্ট্রাক্টর এবং সদস্যরা কোনও অবৈধ memcpyঘটনা ঘটেনি তা পরীক্ষা করার একটি উপায় । (পরীক্ষাটি নির্বোধ নয়, তবে এটি কিছু ধরা পড়ে)। livecountনিশ্চিত করুন যে আপনার ধারক কনস্ট্রাকটর এবং destructors একটি সমান এই নম্বরে কল করেছিলাম করতে একটি সহজ লিক আবিষ্কারক হয়।
মাকিং হাঁস

ঠিক আছে, আমি এটি দেখতে পাচ্ছি, তবে কীভাবে এটি আপনার পুনরুক্তি পরীক্ষা করে? BTW, আমি মনে করি আপনি বোঝানো verifierনা varifier
অ্যাড্রিয়ান

4
@ অ্যাড্রিয়ান না না, আপনি নিজের ধারকটি লিখুন এবং তারপরে এইগুলি একটি গুচ্ছ রাখুন এবং আপনি যে দুর্ঘটনাক্রমে স্মৃতিচারণ করেছেন না তা যাচাই করার জন্য এবং সমস্ত বিধ্বংসকারীকে কল করতে স্মরণীয় করে রাখার জন্য কনটেইনারটি দিয়ে কাজ করুন।
মূক হাঁস

1
আমি কি std::iteratorশিরোনাম থেকে <iterator>
পুনরাবৃত্তির

28

ধারক প্রয়োগের জন্য আপনাকে ধারকগুলি এবং প্রয়োজনীয়তাগুলি সম্পর্কে প্রয়োজনীয় C ++ স্ট্যান্ডার্ড বিভাগটি পড়তে হবে।

সি ++ 03 মানের প্রাসঙ্গিক অধ্যায়টি হ'ল:

বিভাগ 23.1 ধারক প্রয়োজনীয়তা

সি ++ 11 মানের প্রাসঙ্গিক অধ্যায়টি হ'ল:

বিভাগ 23.2 ধারক প্রয়োজনীয়তা

সি ++ 11 স্ট্যান্ডার্ডের নিকট-চূড়ান্ত খসড়া অবাধে উপলভ্য এখানে যায়

আপনি পাশাপাশি, কিছু দুর্দান্ত বই পড়তে পারেন যা ধারকটির ব্যবহারকারীর দৃষ্টিকোণ থেকে প্রয়োজনীয়তাগুলি বুঝতে সহায়তা করবে। দুটি দুর্দান্ত বই যা আমার মনে সহজেই আঘাত করেছিল:

কার্যকরী STL দ্বারাস্কট মায়ার্স
একটি টিউটোরিয়াল এবং রেফারেন্স: সি ++ স্ট্যান্ডার্ড লাইব্রেরী দ্বারাNicolai Josutils


6

এখানে একটি জাল ভেক্টরের খুব সরল বাস্তবায়ন, যা মূলত চারপাশে একটি মোড়ক std::vectorএবং এর নিজস্ব (তবে বাস্তব) পুনরুক্তি রয়েছে, যা এসটিএল পুনরুক্তিকরণকে নকল করে। আবার, পুনরাবৃত্তিকারী খুব সরল, অনেকগুলি ধারণার মতো এড়িয়ে চলেconst_iterator বৈধতা যাচাই বাছাই ইত্যাদি ipping

কোডটি বক্সের বাইরে চলে গেছে।

#include <iostream>
#include <string>
#include <vector>

template<typename T>
struct It
{
    std::vector<T>& vec_;
    int pointer_;

    It(std::vector<T>& vec) : vec_{vec}, pointer_{0} {}

    It(std::vector<T>& vec, int size) : vec_{vec}, pointer_{size} {}

    bool operator!=(const It<T>& other) const
    {
        return !(*this == other);
    }

    bool operator==(const It<T>& other) const
    {
        return pointer_ == other.pointer_;
    }

    It& operator++()
    {
        ++pointer_;            
        return *this;
    }

    T& operator*() const
    {
        return vec_.at(pointer_);   
    }
};

template<typename T>
struct Vector
{
    std::vector<T> vec_;

    void push_back(T item)
    {
        vec_.push_back(item);
    };

    It<T> begin()
    {
        return It<T>(vec_);
    }

    It<T> end()
    {
        return It<T>(vec_, vec_.size());
    }
};

int main()
{
  Vector<int> vec;
  vec.push_back(1);
  vec.push_back(2);
  vec.push_back(3);

  bool first = true;
  for (It<int> it = vec.begin(); it != vec.end(); ++it)
  {
      if (first) //modify container once while iterating
      {
          vec.push_back(4);
          first = false;
      }

      std::cout << *it << '\n'; //print it 
      (*it)++;                  //change it
  }

  for (It<int> it = vec.begin(); it != vec.end(); ++it)
  {
      std::cout << *it << '\n'; //should see changed value
  }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.