简体   繁体   中英

Default Construction of valid Input Iterators

I am designing an input iterator type that enumerates all running processes in a system.

This is similar to an iterator I designed to enumerate modules in a process. The module iterator takes a 'process' object in the constructor, and a default constructed iterator is considered to be the off-the-end iterator.

Example:

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

I do not know what to do about process enumeration though, because there is no 'state' or information that needs to be given to the iterator (everything is handled internally by the iterator using the Windows API).

Example:

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

What is the idiomatic way to deal with this situation? ie Where you need to distinguish between the creation of a 'new' iterator and an off-the-end iterator when nothing needs to be given to the iterator constructor.

If it's relevant, I am able to use C++11 in this library, as long as it's supported by VC11, GCC 4.7, and ICC 12.1.

Thanks.

EDIT:

To clarify, I know that it's not possible to distinguish between the two in the form I've posted above, so what I'm asking is more of a 'design' question than anything else... Maybe I'm just overlooking something obvious though (wouldn't be the first time).

What you really want to do is create a kind of ProcessList object, and base the iterators on that. I wouldn't want to be enumerating all processes or something every time I increment an iterator.

If you create a class that holds the parameters that go into the CreateToolhelp32Snapshot() representing the snapshot you're iterating over, you'll have a natural factory for the iterators. Something like this should work (I'm not on Windows, so not tested):

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);
}

Usage:

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

You could use the 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
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM