C++ 在dynamicDataHolder | C++;
运行此程序并在C++ 在dynamicDataHolder | C++;,c++,C++,运行此程序并在main()中输入值:后,我得到错误“检测到堆损坏”: 我已经花了大约一个小时试图找出是什么原因导致了这一点,希望大家能帮助我解决这一问题,以及我需要做些什么来解决这一问题 谢谢 #include <iostream> using namespace std; template <class t> class dynamicDataHolder { t* ptr = NULL; int size = 0; int elements
main()
中输入值:
后,我得到错误“检测到堆损坏”:
我已经花了大约一个小时试图找出是什么原因导致了这一点,希望大家能帮助我解决这一问题,以及我需要做些什么来解决这一问题
谢谢
#include <iostream>
using namespace std;
template <class t>
class dynamicDataHolder
{
t* ptr = NULL;
int size = 0;
int elements = 0;
public:
dynamicDataHolder() {
ptr = new t[5];
size = 5;
elements = 0;
}
dynamicDataHolder(int arraySize) {
ptr = new t[size];
size = arraySize;
elements = 0;
}
dynamicDataHolder(const dynamicDataHolder<t>& obj) {
ptr = new t[obj.size];
if (ptr != NULL) {
for (int i = 0; i < obj.size; i++) {
ptr[i] = obj.ptr[i];
}
}
else {
cout << "\nPointer to the holder was found to be NULL." << endl;
}
elements = obj.elements;
size = obj.size;
}
t getData(int pos) {
if (pos < 0 || pos > size)
{
cout << "\nError: Invalid index!" << endl;
return 0;
}
return ptr[pos];
}
int sizeA() {
return size;
}
int capacity() {
int capacity = size - elements;
return capacity;
}
void insert(t data) {
int pos;
if (elements >= size) {
int updatedSize = (2 * size);
t* tempPtr = ptr;
ptr = new t[updatedSize];
for (int i = 0; i < size; ++i) {
ptr[i] = tempPtr[i];
}
delete[] tempPtr;
tempPtr = NULL;
size = updatedSize;
pos = elements;
ptr[pos] = data;
incrementElement();
}
else {
if (elements == 0) {
pos = 0;
ptr[pos] = data;
incrementElement();
}
else {
pos = elements;
ptr[pos] = data;
incrementElement();
}
}
}
bool compare(const dynamicDataHolder<t>& obj)
{
bool result = false;
if (obj.size != size || obj.elements != elements) {
return result;
}
for (int i = 0; i < size; i++) {
result = false;
if (ptr[i] == obj.ptr[i])
{
result = true;
}
}
return result;
}
void resize(int updatedSize) {
t* tempPtr = ptr;
ptr = new t[updatedSize];
if (updatedSize < size) {
cout << "\nWarning! Entered size is less than the current size." << endl
<< "Loss of data may occur. Continue? (Y/N)" << endl;
Select:
char userChoice; cin >> userChoice;
if (userChoice == 'y' || userChoice == 'Y') {
goto Continue;
}
else if (userChoice == 'n' || userChoice == 'N') {
return;
}
else {
cout << "\nInvalid selection - please try again." << endl;
goto Select;
}
}
Continue:
if (ptr != NULL) {
for (int i = 0; i < size; i++) {
ptr[i] = tempPtr[i];
}
delete[] tempPtr;
tempPtr = NULL;
size = updatedSize;
}
else {
cout << "\nPointer to the holder was found to be NULL." << endl;
}
}
void insertAtNthPos()
{
cout << "\nEnter the details below to insert values:-\n" << endl;
cout << "\nPosition: ";
int pos = 0; cin >> pos;
cout << "Value: ";
t value; cin >> value;
if (pos <= size)
{
ptr[pos] = value;
if (pos > elements) {
incrementElement();
}
}
else {
resize(2 * size);
ptr[pos] = value;
incrementElement();
}
}
dynamicDataHolder& operator=(const dynamicDataHolder& rhs) {
delete[] ptr;
ptr = new t[rhs.size];
if (this != &rhs)
{
for (int i = 0; i < rhs.size; i++)
{
ptr[i] = rhs.ptr[i];
}
}
return *this;
}
~dynamicDataHolder()
{
delete[] ptr;
ptr = NULL;
}
void incrementElement()
{
elements += 1;
}
};
int main()
{
cout << "What do you want to do?" << endl
<< "\t1. Run Test Sequence" << endl
<< "\t0. Exit Program" << endl;
Select:
int userChoice = 0; cin >> userChoice;
if (userChoice == 1) {
goto testSequence;
}
else if (userChoice == 0) {
return 0;
}
else {
cout << "\nInvalid selection - please try again." << endl;
goto Select;
}
testSequence:
system("CLS");
dynamicDataHolder<int> obj;
dynamicDataHolder<char> obj2(5);
dynamicDataHolder<char> obj3 = obj2;
bool result = (obj3.compare(obj2));
if (result == 1) {
cout << "True" << endl;
}
else {
cout << "\nFalse" << endl;
}
for (int i = 0; i < 5; i++) {
obj.insert(i * 2);
}
cout << "Capacity: " << obj.capacity() << endl;
cout << "Size: " << obj.sizeA() << endl;
obj.resize(15);
cout << obj2.getData(4) << endl;
obj2.insertAtNthPos();
dynamicDataHolder<int> obj4;
obj4 = obj;
}
#包括
使用名称空间std;
模板
类别持有人
{
t*ptr=NULL;
int size=0;
int元素=0;
公众:
动态持有者(){
ptr=新t[5];
尺寸=5;
元素=0;
}
dynamicDataHolder(整数数组化){
ptr=新的t[尺寸];
大小=阵列化;
元素=0;
}
dynamicDataHolder(常量dynamicDataHolder和obj){
ptr=新t【目标尺寸】;
如果(ptr!=NULL){
对于(int i=0;i
这是您的代码的简化版本
- 用循环取代
goto
(语言开发的这场革命发生在1970年,与时俱进!)
- 使用正确的名称
特别是
- 容量意味着“限制潜在大小”(您之前称之为“大小”或“阵列化”)
- 大小表示“集合中元素的计数”(例如,插入时大小会增加)
- (容量-大小)是可用空间/房间/可用容量。这是您之前命名的“容量”
违反对标识符含义的期望会导致错误。事实上,您有错误,因为您自己的测试序列在包含0个元素(\u size==0
)的保持架上使用了getData(4)
)
- 操作也一样。
insert(…)
应该插入,而不是覆盖(见下文),resize(…)
应该更改大小,而不是容量
为了改变容量,标准库使用术语reserve(…)
,我也使用它来保持一致性和最少的惊喜
- 此外,名称应该是描述性的。在强类型语言中,以其类型命名变量是冗余信息。此外,您可以命名变量
strA
,strB
,strC
,但命名givenName
,middleNames
,姓氏>有语义信息(是姓氏
,姓氏
,出生名
,家庭名
。传达了这么多信息)
从这个意义上讲,我将ptr
重命名为\u data
当我们使用时,我们可能会将该类重命名为描述性的:dynaray
告诉您的不仅仅是dynamicDataHolder
(可以是std::optional
,std::unique\u ptr
,std::vector
,harddiskVolume
等)
作为一个次要的脚注,最好为(私有)成员变量制定一个命名约定,这样您就可以知道哪些变量是本地变量,哪些是成员变量
- 你有很多地方(如果我没记错的话,有两个)进行了一次边界检查(想想
pos>容量
,而不是=
)
- 关注点分离。
dynamicDataHolder
是一个数据持有者,而不是一个关于条件的InteractiveUserInterviewAboutorConditions
或databaseUpdateUserInterface
。因此,不要在类中执行UI。将void insertAtNthPos()
更改为void setData(size\t pos,t value)
再次强调,命名是重要的。如果你真的不同意,不要承诺插入,除非它超出了当前的大小限制。“在{1,2,3}的位置1插入7”应该导致“{1,7,2,3}”,而不是“{1,7,3}”。名称setData
- 做预期的事和
- 分离用户界面关注点和
- 漂亮地镜像
getData(大小\u t位置)
- 哦,使用一致的索引类型(在我的版本中为size\t),这样可以避免由于混合有符号/无符号比较而导致的滑稽检查(
pos>0
?)和错误
是的,你有它们。不,你不会抓到它们,因为你没有启用编译器警告。让这强化咒语:“使用强制诊断”
- 不要在全局范围内“使用命名空间”。或者根本不要()
- DRY.DRY.DRY.(不要重复你自己)。这样的例子太多了。你至少有3个复制元素数据循环。你有几个地方可以调整分配的数组的大小。你有一些有趣的东西,比如:
void insert(t data) {
int pos;
if (elements >= size) {
int updatedSize = (2 * size);
t* tempPtr = ptr;
ptr = new t[updatedSize];
for (int i = 0; i < size; ++i) {
ptr[i] = tempPtr[i];
}
delete[] tempPtr;
tempPtr = NULL;
size = updatedSize;
pos = elements;
ptr[pos] = data;
incrementElement();
}
else {
if (elements == 0) {
pos = 0;
ptr[pos] = data;
incrementElement();
}
else {
pos = elements;
ptr[pos] = data;
incrementElement();
}
}
哦,哎呀,这完全被破坏了,因为实际上,插入没有什么特别的。但是setData
也只有~4行代码
- 当你添加物品时,你必须小心:你进行了一次非常有用的“容量检查”。如果容量不足,你会将容量加倍。然而,谁说这足够了?你需要继续加倍,直到空间足够:
void setData(size_t pos, T value) {
while (pos >= _capacity) {
grow();
}
_size = std::max(_size, pos + 1);
_data[pos] = value;
}
或立即保留足够的尺寸:
size_t required = _capacity;
while (pos >= required)
required *= 2;
reserve(required);
- 常量正确性:所有观察者都应标记为
Const
,以便编译器知道它可以优化什么,并且用户保证什么永远不会改变:
size_t size() const { return _size; }
size_t capacity() const { return _capacity; }
size_t available() const { return _capacity - _size; }
bool compare(const DynArray<T>& obj) const;
现在,复制构造函数可以是:
DynArray(DynArray const& obj) : DynArray(obj.capacity()) {
_size = obj.size();
for (size_t i = 0; i < capacity(); ++i)
_data[i] = obj._data[i];
}
现在真正的魔力在于移动构造函数/赋值操作
- 将习惯用法复制和交换到rescue中。事实证明,您可以非常有效地实现这些操作,而且通常只需要很少的代码:
DynArray(DynArray&& obj) : DynArray(0) { swap(obj); }
DynArray& operator=(DynArray rhs) {
swap(rhs);
return *this;
}
请参阅。简单性是一个驱动程序。关键是您只需使用临时性进行交换。临时性将根据您的需要进行破坏。交换本身非常简单:
void swap(DynArray& rhs) {
assert(rhs._data);
std::swap(_capacity, rhs._capacity);
std::swap(_size, rhs._size);
std::swap(_data, rhs._data);
}
复制和交换的背后还有很多想法,但如果您真的愿意,您可以自己找到:
- 比较检查电容
void reserve(size_t updatedSize) {
DynArray tmp(updatedSize);
for (size_t i = 0; i < std::min(capacity(), tmp.capacity()); ++i) {
tmp._data[i] = _data[i];
}
*this = std::move(tmp);
}
void grow() { reserve(2 * _capacity); }
DynArray(DynArray&& obj) : DynArray(0) { swap(obj); }
DynArray& operator=(DynArray rhs) {
swap(rhs);
return *this;
}
void swap(DynArray& rhs) {
assert(rhs._data);
std::swap(_capacity, rhs._capacity);
std::swap(_size, rhs._size);
std::swap(_data, rhs._data);
}
DynArray<int> a(20), b(12);
for (int v : {1,2,3}) { a.insert(v); b.insert(v); }
assert(a == b); // should pass
result = false;
if (ptr[i] == obj.ptr[i])
{
result = true;
}
int main() {
std::cout << "What do you want to do?\n"
<< "\t1. Run Test Sequence\n"
<< "\t0. Exit Program\n";
for (int userChoice = 0; std::cin >> userChoice;) {
switch (userChoice) {
case 1: testSequence(); break;
case 0: return 0;
default: std::cout << "\nInvalid selection - please try again.\n";
}
}
}
#include <iostream>
#include <stdexcept>
#include <cassert>
template <class T> class DynArray {
size_t _capacity = 0;
size_t _size = 0;
T* _data = nullptr;
public:
explicit DynArray(size_t initialCapacity = 5)
: _capacity(initialCapacity),
_data(initialCapacity != 0u ? new T[_capacity]{} : nullptr) {}
DynArray(DynArray const& obj) : DynArray(obj.capacity()) {
_size = obj.size();
for (size_t i = 0; i < capacity(); ++i)
_data[i] = obj._data[i];
}
~DynArray() { delete[] _data; }
void swap(DynArray& rhs) {
assert(rhs._data);
std::swap(_capacity, rhs._capacity);
std::swap(_size, rhs._size);
std::swap(_data, rhs._data);
}
DynArray(DynArray&& obj) : DynArray(0) { swap(obj); }
DynArray& operator=(DynArray rhs) {
swap(rhs);
return *this;
}
T getData(size_t pos) const {
if (pos >= _size) {
throw std::out_of_range("pos");
}
return _data[pos];
}
void setData(size_t pos, T value) {
while (pos >= _capacity)
grow();
_size = std::max(_size, pos+1);
_data[pos] = value;
}
void insert(T data) { setData(_size, data); }
size_t size() const { return _size; }
size_t capacity() const { return _capacity; }
size_t available() const { return _capacity - _size; }
bool compare(const DynArray& obj) const {
if (obj._size != _size) {
return false;
}
for (size_t i = 0; i < _size; i++) {
if (_data[i] != obj._data[i])
return false;
}
return true;
}
void reserve(size_t updatedSize) {
DynArray tmp(updatedSize);
for (size_t i = 0; i < std::min(capacity(), tmp.capacity()); ++i) {
tmp._data[i] = _data[i];
}
*this = std::move(tmp);
}
void grow() { reserve(2 * _capacity); }
};
template <typename T>
void dump(std::string caption, DynArray<T> const& da) {
std::cout << caption << " Capacity: " << da.capacity() << ","
<< " Size: " << da.size() << ","
<< " Available: " << da.available() << ","
<< " Data: {";
for (size_t i = 0; i < da.size(); i++)
std::cout << " " << static_cast<int>(da.getData(i));
std::cout << " }\n";
}
void testSequence() {
{
DynArray<int> obj;
for (size_t i = 0; i < 5; i++) {
obj.insert(i * 2);
}
dump("obj", obj);
if (15 < obj.capacity()) {
std::cout << "\nWarning! Entered size is less than the current size.\n"
<< "Loss of data may occur. Continue? (Y/N)\n";
for (char userChoice; std::cin >> userChoice;) {
if (userChoice == 'y' || userChoice == 'Y') {
obj.reserve(15);
break;
}
if (userChoice == 'n' || userChoice == 'N') {
break;
}
std::cout << "\nInvalid selection - please try again.\n";
}
}
DynArray<int> obj4;
obj4 = obj;
dump("obj4", obj);
}
DynArray<char> obj2(5);
DynArray<char> obj3 = obj2;
dump("obj2", obj2);
dump("obj3", obj3);
std::cout << "obj2 == obj3: " << std::boolalpha << obj3.compare(obj2) << "\n";
try {
std::cout << "obj2.getData(4): " << obj2.getData(4) << std::endl;
} catch(std::out_of_range const& e) {
std::cout << "out of range: " << e.what() << std::endl;
}
while (true) {
std::cout << "\nEnter the details below to insert obj2 values:-\n";
std::cout << "\nPosition: ";
long pos = 0;
if (std::cin >> pos) {
if (pos < 0)
break;
std::cout << "Value: ";
int value = 0;
if (std::cin >> value) {
obj2.setData(pos, value);
}
}
if (!std::cin.eof())
std::cin.clear();
else
break;
dump("obj2", obj2);
}
}
int main() {
do {
std::cout << "What do you want to do?\n"
<< "\t1. Run Test Sequence\n"
<< "\t0. Exit Program\n";
if (int userChoice = 0; std::cin >> userChoice) {
switch (userChoice) {
case 1: testSequence(); continue;
case 0: std::cout << "Goodbye\n"; return 0;
default: std::cout << "\nInvalid selection - please try again.\n";
}
}
if (!std::cin.eof())
std::cin.clear();
} while (std::cin.good());
}
g++ -std=c++17 -O2 -Wall -Wextra -pedantic -pthread -fsanitize=address,undefined main.cpp -o sotest
./sotest <<< "1 30 99 3 42 0 -1 0 8 -1 1 -1 0"