为什么我的右值重载下标运算符没有被调用
Why is my overloaded subscript operator for rvalue not called
我查看了堆栈溢出并不断找到我认为我已经实现的相同示例。我正在尝试实现一个关联数组。我知道有 std::map,但我想自己实现,以便更好地控制和理解。
我已经为左值和右值重载了下标运算符。但是在我的代码中只调用了左值的方法,我找不到我错的地方。任何人都可以指出我正确的方向吗?
这是我的 class 代码。现在,它不应该是高效的,只是工作会让我快乐:
template<typename K, typename V>
class AssocArray {
private:
size_t _arraySize = 0;
K *_keyArray = nullptr;
V *_valueArray = nullptr;
void expandValueArray() {
auto newValueArray = new V[_arraySize];
// copy old values
for (size_t i = 0; i < _arraySize - 1; ++i)
newValueArray[i] = _valueArray[i];
if (_valueArray)
delete[] _valueArray;
_valueArray = newValueArray;
}
void appendToKeyArray(K key) {
auto newKeyArray = new K[_arraySize];
// copy old keys
for (size_t i = 0; i < _arraySize - 1; ++i)
newKeyArray[i] = _keyArray[i];
newKeyArray[_arraySize - 1] = key;
delete[] _keyArray;
_keyArray = newKeyArray;
}
bool keyExists(K key) {
for (size_t i = 0; i < _arraySize; ++i)
if (_keyArray[i] == key)
return true;
return false;
}
size_t getExistingKeyIndex(K key) {
for (size_t i = 0; i < _arraySize; ++i)
if (_keyArray[i] == key)
return i;
}
public:
~AssocArray() {
delete[] _valueArray;
delete[] _keyArray;
}
V operator[](K key) const {
if (keyExists(key))
return _valueArray[getExistingKeyIndex(key)];
else
throw std::out_of_range("Key does not exist");
}
V &operator[](K key) {
if (keyExists(key))
return _valueArray[getExistingKeyIndex(key)];
// key does not exist
++_arraySize;
appendToKeyArray(key);
expandValueArray();
return _valueArray[_arraySize - 1];
}
void print() {
std::cout << "Content of AssocArray:" << std::endl;
if (!_arraySize) std::cout << "none" << std::endl;
for (int i = 0; i < _arraySize; ++i) {
std::cout << "[" << _keyArray[i] << "] => " << _valueArray[i] << std::endl;
}
}
};
我是这样称呼它并产生不良行为的:
#include <iostream>
#include "AssocArray.h"
int main() {
AssocArray<std::string, std::string> assocArray;
(assocArray)["Toni"] = "seven";
(assocArray)["Sam"] = "five";
std::cout << "assocArray before lookup of non existing key:" << std::endl << std::endl;
assocArray.print();
// FixMe: appends key to assocArray, but shouldn't
std::cout << std::endl << "lookup of non existing key:" << std::endl;
auto key = "Megan";
std::cout << "[" << key << "] => " << assocArray[key] << std::endl << std::endl;
std::cout << "assocArray after lookup of non existing key:" << std::endl;
assocArray.print();
}
输出是这样的(看到 Megan 被添加到数组中不应该出现的地方):
assocArray before lookup of non existing key:
Content of AssocArray:
[Toni] => seven
[Sam] => five
lookup of non existing key:
[Megan] =>
assocArray after lookup of non existing key:
Content of AssocArray:
[Toni] => seven
[Sam] => five
[Megan] =>
为什么我没有得到异常?为什么要在这里调用左值的重载方法?
感谢您对此进行调查。
有问题的问题
原来你问错了问题。您遇到了逻辑问题,在这种特殊情况下与成员函数的引用资格无关。在您的代码中,我看不到 AssocArray
是右值 (我们要在其上调用 operator[]
).[=24 的任何使用痕迹=]
为了获得可行的解决方案,我建议您考虑以下两种方法:
- 回想一下,当我们下标
std::map
并且还没有这样的键时,std::map
将使用默认值添加这样的键。这正是您当前实施中发生的情况。为了不在每次我们想要获取一个元素时都插入一个元素,我们有 at()
。所以,你可以只添加等效的 at()
成员函数,它可能会抛出或只是默默地 return 一些默认值,表示没有这样的元素。
- 您可以抛出每个无效的提取。如果下标是在一个有效的键上完成的,那么 return 一个
&
到相应的 mapped_type
(映射到键的值),你可以 read/modify.
引用限定词
你应该考虑区别:
V& operator[]();
V operator[]() const;
比
// An example approach to return types
// You should look mainly on the ref-qualifiers here
V& operator[]() &&; // called on rvalues
const V& operator[]() const&; // called on const and non-const lvalues
在您的 class 中,您有一个 []
return 是获取元素的副本,另一个 []
在 const
实例和 returns 参考。没有运算符可以区分它们是在右值还是左值上调用。
有关引用限定符的更多信息,您可以参考documentation。
我查看了堆栈溢出并不断找到我认为我已经实现的相同示例。我正在尝试实现一个关联数组。我知道有 std::map,但我想自己实现,以便更好地控制和理解。
我已经为左值和右值重载了下标运算符。但是在我的代码中只调用了左值的方法,我找不到我错的地方。任何人都可以指出我正确的方向吗? 这是我的 class 代码。现在,它不应该是高效的,只是工作会让我快乐:
template<typename K, typename V>
class AssocArray {
private:
size_t _arraySize = 0;
K *_keyArray = nullptr;
V *_valueArray = nullptr;
void expandValueArray() {
auto newValueArray = new V[_arraySize];
// copy old values
for (size_t i = 0; i < _arraySize - 1; ++i)
newValueArray[i] = _valueArray[i];
if (_valueArray)
delete[] _valueArray;
_valueArray = newValueArray;
}
void appendToKeyArray(K key) {
auto newKeyArray = new K[_arraySize];
// copy old keys
for (size_t i = 0; i < _arraySize - 1; ++i)
newKeyArray[i] = _keyArray[i];
newKeyArray[_arraySize - 1] = key;
delete[] _keyArray;
_keyArray = newKeyArray;
}
bool keyExists(K key) {
for (size_t i = 0; i < _arraySize; ++i)
if (_keyArray[i] == key)
return true;
return false;
}
size_t getExistingKeyIndex(K key) {
for (size_t i = 0; i < _arraySize; ++i)
if (_keyArray[i] == key)
return i;
}
public:
~AssocArray() {
delete[] _valueArray;
delete[] _keyArray;
}
V operator[](K key) const {
if (keyExists(key))
return _valueArray[getExistingKeyIndex(key)];
else
throw std::out_of_range("Key does not exist");
}
V &operator[](K key) {
if (keyExists(key))
return _valueArray[getExistingKeyIndex(key)];
// key does not exist
++_arraySize;
appendToKeyArray(key);
expandValueArray();
return _valueArray[_arraySize - 1];
}
void print() {
std::cout << "Content of AssocArray:" << std::endl;
if (!_arraySize) std::cout << "none" << std::endl;
for (int i = 0; i < _arraySize; ++i) {
std::cout << "[" << _keyArray[i] << "] => " << _valueArray[i] << std::endl;
}
}
};
我是这样称呼它并产生不良行为的:
#include <iostream>
#include "AssocArray.h"
int main() {
AssocArray<std::string, std::string> assocArray;
(assocArray)["Toni"] = "seven";
(assocArray)["Sam"] = "five";
std::cout << "assocArray before lookup of non existing key:" << std::endl << std::endl;
assocArray.print();
// FixMe: appends key to assocArray, but shouldn't
std::cout << std::endl << "lookup of non existing key:" << std::endl;
auto key = "Megan";
std::cout << "[" << key << "] => " << assocArray[key] << std::endl << std::endl;
std::cout << "assocArray after lookup of non existing key:" << std::endl;
assocArray.print();
}
输出是这样的(看到 Megan 被添加到数组中不应该出现的地方):
assocArray before lookup of non existing key:
Content of AssocArray:
[Toni] => seven
[Sam] => five
lookup of non existing key:
[Megan] =>
assocArray after lookup of non existing key:
Content of AssocArray:
[Toni] => seven
[Sam] => five
[Megan] =>
为什么我没有得到异常?为什么要在这里调用左值的重载方法? 感谢您对此进行调查。
有问题的问题
原来你问错了问题。您遇到了逻辑问题,在这种特殊情况下与成员函数的引用资格无关。在您的代码中,我看不到 AssocArray
是右值 (我们要在其上调用 operator[]
).[=24 的任何使用痕迹=]
为了获得可行的解决方案,我建议您考虑以下两种方法:
- 回想一下,当我们下标
std::map
并且还没有这样的键时,std::map
将使用默认值添加这样的键。这正是您当前实施中发生的情况。为了不在每次我们想要获取一个元素时都插入一个元素,我们有at()
。所以,你可以只添加等效的at()
成员函数,它可能会抛出或只是默默地 return 一些默认值,表示没有这样的元素。 - 您可以抛出每个无效的提取。如果下标是在一个有效的键上完成的,那么 return 一个
&
到相应的mapped_type
(映射到键的值),你可以 read/modify.
引用限定词
你应该考虑区别:
V& operator[]();
V operator[]() const;
比
// An example approach to return types
// You should look mainly on the ref-qualifiers here
V& operator[]() &&; // called on rvalues
const V& operator[]() const&; // called on const and non-const lvalues
在您的 class 中,您有一个 []
return 是获取元素的副本,另一个 []
在 const
实例和 returns 参考。没有运算符可以区分它们是在右值还是左值上调用。
有关引用限定符的更多信息,您可以参考documentation。