【发布时间】:2021-10-13 09:10:07
【问题描述】:
在为 STL Multimap 创建自定义类时,我遇到了一种意外行为,即由 new 运算符创建的动态数组的大小不在 [] 之间。在下面的代码中,在a.Set(3, 'c') 中,存储在newKey 和newSize 中的数组大小为1,而它们的大小应该为2。使用调试器显示,在那行中index 等于 1,所以大小应该是 2。程序不会产生任何异常,但也不会输出预期的结果c。
作为澄清,使用调试器表明在newKey, newSize, newValue 的索引 1 处设置值时会出现问题。它不会抛出任何异常,但也不会改变任何值。
template<typename T>
void Copy(T const* _source, T* _destiny, unsigned long _size)
{
for (unsigned long i = 0; i < _size; i++)
{
_destiny[i] = _source[i];
}
}
template<typename T>
void CopyNew(T const* _source, T* _destiny, unsigned long _size)
{
T* target = new T[_size];
for (unsigned long i = 0; i < _size; i++)
{
target[i] = _source[i];
}
_destiny = target;
}
template<typename T1, typename T2>
class Multimap
{
public:
Multimap() {}
unsigned long Get(T1 const& _key, T2** _return)
{
for (unsigned long i = 0; i < this->keySize_; i++)
{
if (_key == this->key_[i])
{
CopyNew<T2>(this->value_[i], *_return, this->valueSize_[i]);
return i;
}
}
*_return = 0;
return this->keySize_;
}
unsigned long Get(T1 const& _key)
{
for (unsigned long i = 0; i < this->keySize_; i++)
{
if (_key == this->key_[i])
{
return i;
}
}
return this->keySize_;
}
int Set(T1 const& _key, T2 const& _value)
{
T2* target;
unsigned long index = this->Get(_key, &target);
if (target == 0)
{
T1* newKey = new T1[index + 1];
unsigned long* newSize = new unsigned long[index + 1];
T2** newValue = new T2*[this->keySize_ + 1];
if (this->keySize_ != 0)
{
Copy(this->key_, newKey, index);
delete[] this->key_;
Copy(this->valueSize_, newSize, index);
for (unsigned long i = 0; i < this->keySize_; i++)
{
newValue[i] = new T2[this->valueSize_[i]];
Copy(this->value_[i], newValue[i], this->valueSize_[i]);
delete[] this->value_[i];
}
delete[] this->valueSize_;
}
newKey[index] = _key;
newSize[index] = 0;
this->key_ = newKey;
this->valueSize_ = newSize;
this->value_ = newValue;
this->keySize_++;
}
unsigned long newSize = this->valueSize_[index]+1;
T2* newValue = new T2[newSize];
Copy(this->value_[index], newValue, newSize-1);
newValue[newSize-1] = _value;
this->valueSize_[index] = newSize;
this->value_[index] = newValue;
return newSize;
}
unsigned int GetSize()
{
return this->keySize_;
}
protected:
unsigned long keySize_ = 0;
unsigned long* valueSize_ = 0;
T1* key_ = 0;
T2** value_ = 0;
};
int main()
{
Multimap<int, char> a;
a.Set(2, 'b');
a.Set(3, 'c');
char* b;
a.Get(3, &b);
std::cout << b[0];
}
【问题讨论】:
-
检查使用
-g -fsanitize=address,undefined和run tine program 编译时会发生什么。不相关:“_destiny”应该是“_destination”。 -
旁注:明确使用
new和delete,因为C++11 被认为是一种不好的做法。使用std::vector或智能指针。这比学习如何编写自己的模板更重要。 -
写
CopyNew的人不明白参数是如何按值传递的,除非指定为引用类型。_destiny = target;对CopyNew的调用者意味着 nothing。无论作为_destiny参数提供给CopyNew的任何内容都将保持原样(作为奖励,CopyNew因此会泄漏内存以在伤口中添加盐)。 -
@MarekR 但我听说使用任何 STL 类或函数都是不好的做法,因为如果在 DLL 中使用,使用 DLL 的人的 STL 版本可能与用于编译 DLL 的版本不同。 .
-
然后你的DLL被编译器Q编译的程序调用。Q使用不同的后端魔法,它发送给你的DLL的
X实例是不同的形状。卡繁荣。这对您来说可能不是问题。也许您只支持一种编译器和一种编译器版本。否则你的界面只需要处理我们过去称为普通旧数据的简单类型,Standard Layout.
标签: c++ gcc visual-studio-code