在 C++ 中动态分配向量的安全方法是什么
What's the safe way to dynamically allocate vector in C++
动态分配结构后,我认为将 'delete' 放在末尾是明智的。但它给了我一个运行时错误。不过编译没问题。因此,如果我摆脱 'delete',它运行良好。但我担心可能会发生内存泄漏。处理此代码的安全方法是什么?
#include <iostream>
#include <vector>
using namespace std;
typedef struct
{
vector<char*> vstr;
vector<int> vint;
}VecStrInt;
int main()
{
VecStrInt * mtx = new VecStrInt();
mtx[0].vstr.push_back("Hello");
mtx[0].vint.push_back(1);
cout<<mtx[0].vint.at(0)<<endl;
cout<<mtx[0].vstr.at(0)<<endl;
//delete [] mtx;
return 0;
}
delete[]
的调用与delete
的调用不同(注意方括号)
您将 delete
的调用与 new
的调用配对,并将 delete[]
的调用与 new SomeType[someCount]
的调用配对。
在你的例子中,你分配了一个对象,而不是一个数组。您的对象恰好 表示 一个向量,它是一个数组,但这对 C++ 无关紧要:您用 "single" new
分配了它,所以您不能对其应用 "array" delete[]
。
因此,您需要 delete
使用常规删除运算符:
delete mtx;
注意:很少有需要动态分配 std::vector<T>
的情况。表示std::vector<T>
的对象本身很小;数据存储在别处,并动态分配。所以你不妨使用
VecStrInt mtx;
并完全跳过 delete
。
如果像这样只分配一个对象,则必须使用运算符 delete
VecStrInt * mtx = new VecStrInt();
//...
delete mtx;
如果你分配一个对象数组(即使数组只包含一个元素)你必须像这样使用运算符delete[]
VecStrInt * mtx = new VecStrInt[1];
//...
delete [] mtx;
您也可以使用标准智能指针,例如 std::unique_ptr
。
如果你真的想要安全,你不应该像这样直接使用new
/delete
,因为在你的函数和[=13=中间可能会抛出异常] 子句将不会被执行。
分配和解除分配事物的 C++ 方法是通过 constructors/destructors 完成的,称为 RAII。标准 类 通过他们的 constructor/destructor 为您处理。您可以使用例如:
- 标准容器,如
std::vector<T>
用于多个元素,而不是 T* = new T[]
std::string
用于字符串而不是 char*
- 智能指针,由C++11标准引入(仅适用于更复杂的情况):
std::unique_ptr<T>
或std::shared_ptr<T>
/std::weak_ptr<T>
注意:在你的例子中,mtx
只在main
函数内部使用,所以你不需要在堆上分配它,你可以只写:
int main()
{
VecStrInt mtx;
mtx.vstr.push_back("Hello");
mtx.vint.push_back(1);
cout << mtx.vint.at(0) << endl;
cout << mtx.vstr.at(0) << endl;
return 0;
}
同样,你应该在VecStrInt
中使用std::string
而不是char*
,以避免字符串内存泄漏:
#include <string>
struct VecStrInt
{
vector<string> vstr;
vector<int> vint;
};
动态分配结构后,我认为将 'delete' 放在末尾是明智的。但它给了我一个运行时错误。不过编译没问题。因此,如果我摆脱 'delete',它运行良好。但我担心可能会发生内存泄漏。处理此代码的安全方法是什么?
#include <iostream>
#include <vector>
using namespace std;
typedef struct
{
vector<char*> vstr;
vector<int> vint;
}VecStrInt;
int main()
{
VecStrInt * mtx = new VecStrInt();
mtx[0].vstr.push_back("Hello");
mtx[0].vint.push_back(1);
cout<<mtx[0].vint.at(0)<<endl;
cout<<mtx[0].vstr.at(0)<<endl;
//delete [] mtx;
return 0;
}
delete[]
的调用与delete
的调用不同(注意方括号)
您将 delete
的调用与 new
的调用配对,并将 delete[]
的调用与 new SomeType[someCount]
的调用配对。
在你的例子中,你分配了一个对象,而不是一个数组。您的对象恰好 表示 一个向量,它是一个数组,但这对 C++ 无关紧要:您用 "single" new
分配了它,所以您不能对其应用 "array" delete[]
。
因此,您需要 delete
使用常规删除运算符:
delete mtx;
注意:很少有需要动态分配 std::vector<T>
的情况。表示std::vector<T>
的对象本身很小;数据存储在别处,并动态分配。所以你不妨使用
VecStrInt mtx;
并完全跳过 delete
。
如果像这样只分配一个对象,则必须使用运算符 delete
VecStrInt * mtx = new VecStrInt();
//...
delete mtx;
如果你分配一个对象数组(即使数组只包含一个元素)你必须像这样使用运算符delete[]
VecStrInt * mtx = new VecStrInt[1];
//...
delete [] mtx;
您也可以使用标准智能指针,例如 std::unique_ptr
。
如果你真的想要安全,你不应该像这样直接使用new
/delete
,因为在你的函数和[=13=中间可能会抛出异常] 子句将不会被执行。
分配和解除分配事物的 C++ 方法是通过 constructors/destructors 完成的,称为 RAII。标准 类 通过他们的 constructor/destructor 为您处理。您可以使用例如:
- 标准容器,如
std::vector<T>
用于多个元素,而不是T* = new T[]
std::string
用于字符串而不是char*
- 智能指针,由C++11标准引入(仅适用于更复杂的情况):
std::unique_ptr<T>
或std::shared_ptr<T>
/std::weak_ptr<T>
注意:在你的例子中,mtx
只在main
函数内部使用,所以你不需要在堆上分配它,你可以只写:
int main()
{
VecStrInt mtx;
mtx.vstr.push_back("Hello");
mtx.vint.push_back(1);
cout << mtx.vint.at(0) << endl;
cout << mtx.vstr.at(0) << endl;
return 0;
}
同样,你应该在VecStrInt
中使用std::string
而不是char*
,以避免字符串内存泄漏:
#include <string>
struct VecStrInt
{
vector<string> vstr;
vector<int> vint;
};