简体   繁体   中英

Determining Purpose of operator[] Usage

Let's say I have something like the following method in my container class:

Datatype& operator[](const unsigned int Index) // I know this should use size_t instead.
{
    return *(BasePointer + Index); // Where BasePointer is the start of the array.
}

I'd like to implement some sort of bounds-checking for the MyInstance[Index] = Value usage so the container resizes automatically if the user tries to change a value outside its range. However, I want something else to happen if the user tries to access a value outside the container's range, eg MyVariable = MyInstance[Index] . How can I detect how operator[] is being used?

Sketch:

return a proxy object instead of the actual data entry. The proxy object then defines operator = to handle the assignment case, and an implicit conversion operator for the reading-out case.

template <typename T>
class AccessorProxy {
  friend class Container<T>;
public:
    AccessorProxy(Container<T>& data, unsigned index)
        : data(data), index(index) { }
    void operator =(T const& new_value) {
        // Expand array.
    }
    operator const T&() const {
        // Do bounds check.
        return *(data.inner_array + index);
    }
private:
    AccessorProxy(const AccessorProxy& rhs)
     : data(rhs.data), index(rhs.index) {}
    AccessorProxy& operator=(const AccessorProxy&);
    Container<T>& data;
    unsigned index;
};

template <typename T>
class ConstAccessorProxy {
  friend class Container<T>;
public:
    ConstAccessorProxy(const Container<T>& data, unsigned index)
        : data(data), index(index) { }
    operator const T&() const {
        // Do bounds check.
        return *(data.inner_array + index);
    }
private:
    ConstAccessorProxy(const ConstAccessorProxy& rhs)
     : data(rhs.data), index(rhs.index) {}
    ConstAccessorProxy& operator=(const ConstAccessorProxy&);
    const Container<T>& data;
    unsigned index;
};

AccessorProxy<Datatype> operator[](const unsigned int Index)
{
    return AccessorProxy<Datatype>(*this, Index);
}
ConstAccessorProxy<Datatype> operator[] const (const unsigned int Index)
{
    return ConstAccessorProxy<Datatype>(*this, Index);
}

The accessor classes will likely need to be be friends of the container class.

Finding ways to avoid the code duplication is left as an exercise to the reader. :)

Use a dummy class type to represent expressions like MyInstance[Index] and delay figuring out what to do until that expression is used.

class MyContainer {
private:
    class IndexExpr {
    public:
        // Get data from container:
        operator const Datatype&() const;
        // Expand container if necessary, then store data:
        Datatype& operator=(const Datatype& value);

        // Treat MyInstance[i] = MyInstance[j]; as expected:
        Datatype& operator=(const IndexExpr& rhs)
        { return *this = static_cast<const Datatype&>(rhs); }
    private:
        IndexExpr(MyContainer& cont, unsigned int ind);
        MyContainer& container_;
        unsigned int index_;
        friend class MyContainer;
    };

public:
    IndexExpr operator[](unsigned int Index)
    { return IndexExpr(*this, Index); }

    // No IndexExpr needed when container is const:
    const Datatype& operator[](unsigned int Index) const;

    // ...
};

This is not a perfect answer to "how to detect", but, if the user is accessing the operator[] via a const instance, then throw an exception if the index is out of bounds. ie

Datatype const& operator[]() const { .. // don't modify here, throw exception

However, if the user is accessing the instance via a non const instance, then by all means expand if the index is out of bounds (and within your acceptable ranges)

Datatype& operator[]() { .. // modify here

Basically, you are using the const attribute of the instance to determine what your semantics would be (as done in std::map - ie trying to call operator[] on a const instance of a map results in a compiler error - ie there is no const qualified operator[] for map, because the function is guaranteed to create a mapping if the key does not exist already.)

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