【问题标题】:Default Construction of valid Input Iterators有效输入迭代器的默认构造
【发布时间】:2012-06-18 17:55:39
【问题描述】:

我正在设计一个枚举系统中所有正在运行的进程的输入迭代器类型。

这类似于我为枚举进程中的模块而设计的迭代器。模块迭代器在构造函数中接受一个“进程”对象,并且默认构造的迭代器被认为是离线迭代器。

例子:

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;

处理这种情况的惯用方法是什么?即,当不需要向迭代器构造函数提供任何内容时,您需要区分“新”迭代器和非终端迭代器的创建。

如果相关,我可以在这个库中使用 C++11,只要它受 VC11、GCC 4.7 和 ICC 12.1 支持。

谢谢。

编辑:

为了澄清,我知道无法以我上面发布的形式区分两者,所以我要问的是一个“设计”问题而不是其他任何问题......也许我是只是忽略了一些明显的东西(不会是第一次)。

【问题讨论】:

  • 让默认构造元素成为“结束”迭代器,然后使用另一个构造函数来构造“开始”状态。然后写两个非成员函数:begin_modules()end_modules()
  • @JamesMcNellis:我目前的解决方法是使用一个虚拟参数来表示“真正的”迭代器,这样会很好地工作。

标签: c++ windows iterator c++11


【解决方案1】:

您真正想做的是创建一种 ProcessList 对象,并以此为基础创建迭代器。我不想在每次增加迭代器时都枚举所有进程或其他内容。

【讨论】:

  • 每次递增迭代器时,它都会移动到下一个进程。 Windows API 自动处理后台快照。迭代器增量上发生的所有事情都是对 Process32Next 的调用。
【解决方案2】:

如果您创建一个类来保存进入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;
}

【讨论】:

  • 我实际上是在试图避免这种情况,因为它起初看起来像是过度设计,但经过反思,它确实似乎是更“自然”的设计。它似乎也更适合现代 C++ 习惯用法/功能,例如示例代码中的 range-for 循环。
【解决方案3】:

您可以使用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
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-14
    • 1970-01-01
    • 2017-07-07
    • 1970-01-01
    • 1970-01-01
    • 2023-01-03
    • 2020-06-20
    • 2023-03-20
    相关资源
    最近更新 更多