我正在写一个要求我实现自己的(基本)矢量类的作业。一个不寻常的要求是,我们必须提供一个函数,该函数给出向量中所有元素的总和。此函数应缓存总和,因此如果向量未更改,则可以在固定时间内回答后续调用。
我遇到的问题是在发生变化时想出来。
#include <iostream>
class MyVector {
int* v;
int size;
int totalSum;
bool upToDate;
public:
MyVector(int size) : size{size}, totalSum{0}, upToDate{false} {
v = new int[size];
for(int i = 0; i < size; i++) {
v[i] = 0;
}
}
// Set - should only be called as an lvalue
int& operator[](unsigned int i) {
upToDate = false;
std::cerr << "Set\n";
return v[i];
}
// Get - should only be called as an rvalue
int operator[](unsigned int i) const {
std::cerr << "Get\n";
return v[i];
}
// Get sum of array -- result is cached for performance
int sum() {
if(!upToDate) {
upToDate = true;
totalSum = 0;
for(int i = 0; i < size; i++) {
totalSum += v[i];
}
}
return totalSum;
}
};
int main() {
MyVector mv(3);
mv[0] = 1;
mv[1] = 2;
mv[2] = 3;
std::cout << "Sum " << mv.sum() << "\n";
int first = mv[0];
std::cout << "First element is " << first << "\n";
std::cout << "Sum " << mv.sum() << "\n";
}
我提供了[]运算符的两个重载版本 - 一个用于获取,一个用于设置。无论何时调用运算符的设置版本,我都假设正在更改向量。
# Output
Set
Set
Set
Sum 6
Set
First element is 1
Sum 6
但是,似乎操作符的设置版本总是被调用,即使它被用作右值。
如何正确地重载[]运算符以区分其用于获取和设置?
答案 0 :(得分:2)
您可以返回围绕该引用的瘦代理包装器,而不是直接返回对存储的int的引用,该引用可以监视更改。在大多数情况下,编译器应该内联并优化它(您可以尝试对其进行基准测试并进行比较)。
包装类:
class Item {
int &value;
MyVector &myVector;
public:
Item(int &value, MyVector &myVector) : value(value), myVector(myVector) {}
Item& operator=(int newvalue) {
std::cerr << "Set\n";
value = newvalue;
myVector.upToDate = false;
return *this;
}
// TODO: Reimplement also operators like +=, -=, etc
// You can use boost helpers for that.
operator int() const {
std::cerr << "Get\n";
return value;
}
};
对MyVector的更改:
class MyVector {
// ...
Item operator[](unsigned int i) {
return Item(v[i], *this);
}
const int operator[](unsigned int i) const {
std::cerr << "Const Get\n";
return v[i];
}
// ...
}
它可以完全相同的方式使用:
int main() {
MyVector mv(3);
mv[0] = 1;
mv[1] = 2;
mv[2] = 3;
std::cout << "Sum " << mv.sum() << "\n";
int first = mv[0];
std::cout << "First element is " << first << "\n";
std::cout << "Sum " << mv.sum() << "\n";
}