2012-06-18 31 views
4

我正在設計一個枚舉系統中所有正在運行的進程的輸入迭代器類型。有效輸入迭代器的缺省構造

這與設計用於枚舉過程中模塊的迭代器很相似。模塊迭代器在構造函數中使用'process'對象,並且默認構造的迭代器被認爲是非臨時迭代器。

例子:

hadesmem::ModuleIterator beg(process); 
hadesmem::ModuleIterator end; 
assert(beg != end); 

我不知道該怎麼做的過程枚舉,但因爲沒有「國家」或信息需要被提供給迭代器(一切由迭代器內部處理使用Windows API)。

例子:

// This is obviously a broken design, what is the best way to distinguish between the two? 
hadesmem::ProcessIterator beg; 
hadesmem::ProcessIterator end; 

什麼是處理這種情況的慣用方法是什麼?即當需要爲迭代器構造函數提供任何內容時,需要區分創建「新」迭代器和異端迭代器的位置。

如果相關,只要VC11,GCC 4.7和ICC 12.1支持,我就可以在這個庫中使用C++ 11。

謝謝。

編輯:

爲了澄清,我知道這是不可能的兩人在我上面貼的形式來區分,那麼我現在問的是比什麼都重要一個「設計」問題......也許我只是忽略了一些顯而易見的東西(不會是第一次)。

+2

默認的構造元素是'end'迭代器,然後有另一個構造函數來構造'begin'狀態。然後編寫兩個非成員函數:'begin_modules()'和'end_modules()'。 –

+0

@JamesMcNellis:我目前的解決方法是使用虛擬參數來表示'真正'的迭代器,所以這將很好地工作。 – RaptorFactor

回答

1

如果您創建了一個保存代表要迭代的快照的CreateToolhelp32Snapshot()參數的類,那麼您將擁有一個迭代器的自然工廠。像這樣的東西應該工作(我不是在Windows上,所以未測試):

class Process; 
class Processes { 
    DWORD what, who; 
public: 
    Processes(DWORD what, DWORD who) : what(what), who(who) {} 

    class const_iterator { 
     HANDLE snapshot; 
     LPPROCESSENTRY32 it; 
     explicit const_iterator(HANDLE snapshot, LPPROCESSENTRY32 it) 
      : snapshot(snapshot), it(it) {} 
    public: 
     const_iterator() : snapshot(0), it(0) {} 

     // the two basic functions, implement iterator requirements with these: 
     const_iterator &advance() { 
      assert(snapshot); 
      if (it && !Process32Next(snapshot, &it)) 
       it = 0; 
      return *this; 
     } 
     const Process dereference() const { 
      assert(snapshot); assert(it); 
      return Process(it); 
     } 
     bool equals(const const_iterator & other) const { 
      return handle == other.handle && it == other.it; 
     } 
    }; 

    const_iterator begin() const { 
     const HANDLE snapshot = CreateToolhelp32Snapshot(what, who); 
     if (snapshot) { 
      LPPROCESSENTRY32 it; 
      if (Process32First(snapshot, &it)) 
       return const_iterator(snapshot, it); 
     } 
     return end(); 
    } 
    const_iterator end() const { 
     return const_iterator(snapshot, 0); 
    } 
}; 

inline bool operator==(Processes::const_iterator lhs, Processes::const_iterator rhs) { 
    return lhs.equals(rhs); 
} 
inline bool operator!=(Processes::const_iterator lhs, Processes::const_iterator rhs) { 
    return !operator==(lhs, rhs); 
} 

用法:

int main() { 
    const Processes processes(TH32CS_SNAPALL, 0); 
    for (const Process & p : processes) 
     // ... 
    return 0; 
} 
+0

我實際上是在試圖避免這個問題,因爲它似乎起初就像過度工程,但是在反思中它似乎確實是更「自然」的設計。它也似乎更好地用現代C++習語/功能凝聚,例如示例代碼中的range-for循環。 – RaptorFactor

2

你真正想要做的是創建一種ProcessList對象,並在其上設置迭代器。我不希望枚舉所有進程或每次增加迭代器時發生的事情。

+2

每次增加迭代器時,它都會轉到下一個進程。 Windows API會自動處理快照。在迭代器增量上發生的所有事情都是對Process32Next的調用。 – RaptorFactor

+0

關於第二個想法,我認爲你實際上是在正確的軌道上... – RaptorFactor

1

你可以使用named constructor idiom

class ProcessIterator 
private: 
    ProcessIterator(int) //begin iterator 
    ProcessIterator(char) //end iterator 
    //no default constructor, to prevent mistakes 
public: 
    friend ProcessIterator begin() {return ProcessIterator(0);} 
    friend ProcessIterator end() {return ProcessIterator('\0');} 
} 

int main() { 
    for(auto it=ProcessIterator::begin(); it!=ProcessIterator::end(); ++it) 
     //stuff 
}