簡體   English   中英

封裝標准容器的重載運算符++

[英]Overload operator++ for encapsulated standard container

我封裝了一個std :: list,使其在進行迭代時可以安全地進行迭代,並且有可能將內容標記為“無效”,並且在迭代過程中跳過了“無效”內容。 具體而言,在迭代過程中,當前對象可以調度自己或其他對象以從列表中刪除並將這些對象標記為無效。 然后定期清除列表中的無效對象。

如何定義增量運算符以使基於范圍的for循環正常工作? 這是我的課:

template <typename T> class DeferredCleanupList
{
public:
    DeferredCleanupList() {
        (void)static_cast<Valid *>((T)0);
    }
    virtual ~DeferredCleanupList() {}

    typedef typename std::list<T>::iterator iterator;

    iterator begin() {
        iterator it = container.begin();

        if ((*it)->valid())
            return it;

        return next(it);
    }
    iterator next(iterator it) {
        do {
            ++it;
        }
        while (it != end() && !(*it)->valid());

        return it;
    }
    iterator end() { return container.end(); }

//    to be implemented:
//    typedef typename std::list<T>::const_iterator const_iterator ;
//    const_iterator cbegin() const { return container.cbegin(); }
//    const_iterator cend() const { return container.cend(); }
//    const_iterator cnext() const { ??? }

    size_t size() const { return container.size(); }

    void add(T *ptr) { container.push_front(ptr); }
    void remove(T *ptr) { ptr->invalidate(); }

    // called occasionally
    void delete_invalid() {
        for (auto it = container.begin(); it != container.end(); ) {
            auto ptr = *it;
            if (ptr->valid())
                ++it;
            else {
                delete ptr;
                it = container.erase(it);
            }
        }
    }

private:
    DeferredCleanupList(const DeferredCleanupList&);
    DeferredCleanupList& operator=(const DeferredCleanupList&);

    std::list<T> container;
};

我當前的測試用例是這樣的:

int main() {
    class D : public Valid {};

    DeferredCleanupList<D *> list;

    for (auto it = list.begin(); it != list.end(); it = list.next(it)); // works
    for (auto ptr : list); // iterates, but doesn't call list.next(it)
}

編輯:經過一番嘗試和錯誤后,我根據注釋中的建議編寫了此迭代器包裝器:

template <typename T> class DeferredCleanupList
{
public:
    class iterator {
    public:
        iterator(typename std::list<T>::iterator it, DeferredCleanupList<T>& ls) : it(it), list(ls) {}

        iterator& operator=(const iterator& rhs) { it = rhs; return *this; }
        iterator& operator++() {
            do {
                ++it;
            }
            while (it != list.end().it && !(*it)->valid());

            return *this;
        }
        friend bool operator==(const iterator& lhs, const iterator& rhs) { return lhs.it == rhs.it; }
        friend bool operator!=(const iterator& lhs, const iterator& rhs) { return !(lhs == rhs); }

        T& operator*() { return *it; }

    private:
        typename std::list<T>::iterator it;
        DeferredCleanupList& list;
    };

    iterator begin() {
        iterator it = iterator(container.begin(), *this);

        if (it == end() || (*it)->valid())
            return it;

        return ++it;
    }

    iterator end() { return iterator(container.end(), *this); }
}

在我拋出的所有測試用例中,它似乎都能正常工作。 我是否缺少使用此方法的任何明顯內容? 有沒有更優雅的解決方案?

http://en.cppreference.com/w/cpp/language/range-for

上面的語法產生的代碼等效於以下內容(__range,__ begin和__end僅用於說明):

 { auto && __range = range_expression ; for (auto __begin = begin_expr, __end = end_expr; __begin != __end; ++__begin) { range_declaration = *__begin; loop_statement } } 

也就是說,您必須定義預增量運算符。

您不能在容器類中執行此操作。 您應該實現自己的迭代器,並在其前綴增量運算符中實現所需的行為。 您可以通過幾種方法來做到這一點,包括從STL 繼承一種方法或為std :: list迭代器創建自己的包裝器。

實際上,要在迭代器中實現所需的行為,您需要向自定義迭代器類提供容器的最終迭代器

我不建議您實現自己的迭代器,除非您的設計實際上對它們有用。 不必要的並發症幾乎總是導致更多不必要的並發症。

我已經修改了您的代碼,因此它實際上可以編譯並實現std :: list迭代器包裝程序,以按您的計划進行操作。

#include <iostream>
#include <list>
#include <iterator>

using namespace std;

class Valid {};

template<typename _Tp>
struct myIteratorWrapper
{

  typedef myIteratorWrapper<_Tp>         _Self;
  typedef _Tp               value_type;
  typedef _Tp*                 pointer;
  typedef _Tp&               reference;

  typedef typename std::list<_Tp>::iterator listIterator;

  listIterator it;
  listIterator itEnd;

  myIteratorWrapper(const listIterator& listIterArg) _GLIBCXX_NOEXCEPT
    : it(listIterArg)
  {}

  myIteratorWrapper(const listIterator& itBegin,
            const listIterator& itEnd) _GLIBCXX_NOEXCEPT
    : it(itBegin), itEnd(itEnd)
  {}

  reference
  operator*() const _GLIBCXX_NOEXCEPT
  { return *it; }

  pointer
  operator->() const _GLIBCXX_NOEXCEPT
  { return &(*it); }

  /* Change logic of this method as you wish, but keep the signature */ 
  _Self&
  operator++() _GLIBCXX_NOEXCEPT
  {
    do
    {
      ++it;
    }while (it != itEnd && !(*it)->valid());

    return *this;
  }

  bool
  operator==(const _Self& __x) const _GLIBCXX_NOEXCEPT
  { return it == __x.it; }

  bool
  operator!=(const _Self& __x) const _GLIBCXX_NOEXCEPT
  { return it != __x.it; }
};

template <typename T> class DeferredCleanupList
{
public:
  DeferredCleanupList() {
    (void)static_cast<Valid *>((T)0);
  }
  virtual ~DeferredCleanupList() {}

  typedef myIteratorWrapper<T> iterator;

  iterator begin() {
    iterator it(container.begin(), container.end());
    return it;
  }

  iterator next(iterator it) {       
    return ++it;
  }

  iterator end() { return container.end(); }

  size_t size() const { return container.size(); }

  void add(T ptr) { container.push_front(ptr); }
  void remove(T ptr) { ptr->invalidate(); }

  // called occasionally
  void delete_invalid() {
    for (auto it = container.begin(); it != container.end(); ) {
      auto ptr = *it;
      if (ptr->valid())
    ++it;
      else {
    delete ptr;
    it = container.erase(it);
      }
    }
  }

private:
  DeferredCleanupList(const DeferredCleanupList&);
  DeferredCleanupList& operator=(const DeferredCleanupList&);

  std::list<T> container;
};

class D : public Valid {
  bool isValid;
  std::string myName;
public:

  D(std::string myName, bool arg = false)
    : myName(myName), isValid(arg) {}

  bool valid() const
  { return isValid; }

  const std::string& whoAmI() const
  { return myName; }
};

int main() {
  D o1("o1", true);
  D o2("o2");
  D o3("o3", true);
  D o4("o4");
  D o5("o5", true);

  DeferredCleanupList<D *> list;
  list.add(&o1);
  list.add(&o2);
  list.add(&o3);
  list.add(&o4);
  list.add(&o5);

  for (auto ptr : list)
    {
      std::cout << ptr->whoAmI() << std::endl;
    }
}

輸出:

o5
o3
o1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM