0

I have a class which allows me to access a vectors value:

Class Image{
    public:
        Image(int rows, int cols): cols_(cols), rows_(rows), data_(rows*cols,0) {};
        int& at(int row, int col){
            return data_.at(col*row);
        };
    private:
        int rows_ = 0;
        int cols_ = 0;
        const int max_val_ = 255;
        std::vector<int> data_;

Currently this lets me perform

int num = image.at(row, col);
// or
image.at(row, col) = 10;

My question is how to I limit the values of data_ to not allow an assignment more than max_value_? I.e image.at(row,col) = 256;

Cr1064
  • 409
  • 5
  • 15
  • 3
    You can't do that if you return an `int&`. You would have to return a proxy object (or use an interface like `void set(int row, int col, int value)`). – Max Langhof Oct 18 '19 at 11:32
  • 5
    Note that your index calculation is probably wrong. You want `row*cols_ + cols` for row major and `col*rows_+rows` for col major order. – Timo Oct 18 '19 at 11:34
  • Suggesting https://stackoverflow.com/questions/994488/what-is-proxy-class-in-c as duplicate. There is also a good discussion of benefits/drawbacks in https://stackoverflow.com/questions/22980171/array-subscription-returning-reference-vs-proxy-class-method. – Max Langhof Oct 18 '19 at 11:35
  • 1
    @Timo I have noticed this but ignored for the question. – Cr1064 Oct 18 '19 at 11:35
  • @Eljay The .at method should catch this exception, it's not exactly what I'm asking – Cr1064 Oct 18 '19 at 11:41
  • I missed the gist. Got it now, thank you. I deleted my irrelevant comment. Max's advice on having a setter interface to guarantee the caller doesn't violate the invariant is the way I'd go. – Eljay Oct 18 '19 at 11:45
  • You can use uint8_t for the data type. This limits the values to 0-255. – ChrisMM Oct 18 '19 at 12:14

1 Answers1

0

Like Max Langhof said, you can use a proxy object like this:

class AssignmentProxy
{
public:
    AssignmentProxy(int& value, int min, int max) : value_(value), min_(min), max_(max) { }
    AssignmentProxy& operator=(int value)
    {
        if (value >= min_ && value < max_)
            value_ = value;
        else 
            throw std::invalid_argument("no");

        return *this;
    }

    operator int() const noexcept
    {
        return value_;
    }

private:
    int min_, max_;
    int& value_;
};

The implicit conversion to int is questionable but justified I think, since this only a proxy that mimics an integer.

Here is a full example.

Timo
  • 9,269
  • 2
  • 28
  • 58