我知道如何在C中为数组动态分配空间。可以按如下方式完成:
L = (int*)malloc(mid*sizeof(int));
内存可以通过以下方式释放:
free(L);
如何在 C++ 中实现等效功能?
具体来说,如何使用
new
和 delete[]
关键字?特别是在创建/销毁链表节点,或者创建和销毁其大小在编译期间由变量给定的数组的情况下?
int* L = new int[mid];
delete[] L;
对于数组(这就是你想要的)或
int* L = new int;
delete L;
对于单个元素。
但是使用向量更简单,或者使用智能指针,那么你不必担心内存管理。
std::vector<int> L(mid);
L.data()
使您可以访问 int[]
数组缓冲区,稍后您可以 L.resize()
向量。
auto L = std::make_unique<int[]>(mid);
L.get()
为您提供指向 int[]
数组的指针。
以下信息将会有用: 来源:https://www.learncpp.com/cpp-tutorial/6-9a-dynamically-alhaving-arrays/
初始化动态分配的数组
如果要将动态分配的数组初始化为 0,语法非常简单:
int *array = new int[length]();
在 C++11 之前,没有简单的方法将动态数组初始化为非零值(初始化列表仅适用于固定数组)。这意味着您必须循环遍历数组并显式分配元素值。
int *array = new int[5];
array[0] = 9;
array[1] = 7;
array[2] = 5;
array[3] = 3;
array[4] = 1;
超级烦人!
但是,从 C++11 开始,现在可以使用初始值设定项列表来初始化动态数组!
int fixedArray[5] = { 9, 7, 5, 3, 1 }; // initialize a fixed array in C++03
int *array = new int[5] { 9, 7, 5, 3, 1 }; // initialize a dynamic array in C++11
请注意,此语法在数组长度和初始值设定项列表之间没有运算符=。
为了保持一致性,在C++11中,固定数组也可以使用统一初始化来初始化:
int fixedArray[5] { 9, 7, 5, 3, 1 }; // initialize a fixed array in C++11
char fixedArray[14] { "Hello, world!" }; // initialize a fixed array in C++11
需要注意的是,在 C++11 中,您无法从 C 样式字符串初始化动态分配的 char 数组:
char *array = new char[14] { "Hello, world!" }; // doesn't work in C++11
如果您需要这样做,请动态分配 std::string (或分配 char 数组,然后 strcpy 中的字符串)。
另请注意,必须使用显式长度声明动态数组:
int fixedArray[] {1, 2, 3}; // okay: implicit array size for fixed arrays
int *dynamicArray1 = new int[] {1, 2, 3}; // not okay: implicit size for dynamic arrays
int *dynamicArray2 = new int[3] {1, 2, 3}; // okay: explicit size for dynamic arrays
使用
new
运算符分配内存,并使用 delete
运算符释放指针。请注意,您无法删除普通变量,只能在完成任务后删除指针和数组。
int * foo;
foo = new int [5];
delete[] foo;
完整的程序
#include <iostream>
#include <new>
using namespace std;
int main ()
{
int i,n;
int * p;
cout << "How many numbers would you like to type? ";
cin >> i;
p= new (nothrow) int[i];
if (p == nullptr)
cout << "Error: memory could not be allocated";
else
{
for (n=0; n<i; n++)
{
cout << "Enter number: ";
cin >> p[n];
}
cout << "You have entered: ";
for (n=0; n<i; n++)
cout << p[n] << ", ";
delete[] p;
}
return 0;
}
结果
How many numbers would you like to type? 5
Enter number : 75
Enter number : 436
Enter number : 1067
Enter number : 8
Enter number : 32
You have entered: 75, 436, 1067, 8, 32,
在 C++ 中,我们有分配和取消分配动态内存的方法。可以使用
new
运算符 as, 动态分配变量
type_name *variable_name = new type_name;
数组只不过是连续内存位置的集合,因此,我们可以在 C++ 中动态分配数组,
type_name *array_name = new type_name[SIZE];
并且您可以使用
delete
来释放动态分配的空间,如下所示,
对于变量,
delete variable_name;
对于数组,
delete[] array_name;
在动态内存中使用原始指针时需要非常小心,但这是一个简单的示例。
int main() {
// Normal Pointer To Type
int* pX = nullptr;
pX = new int;
*pX = 3;
std::cout << *pX << std::endl;
// Clean Up Memory
delete pX;
pX = nullptr;
// Pointer To Array
int* pXA = nullptr;
pXA = new int[10]; // 40 Bytes on 32bit - Not Initialized All Values Have Garbage
pXA = new int[10](0); // 40 Bytes on 32bit - All Values Initialized To 0.
// Clean Up Memory To An Array Of Pointers.
delete [] pXA;
pXA = nullptr;
return 0;
} // main
避免内存泄漏;悬空指针、提前删除内存等。尝试使用智能指针。它们有两种类型:共享的和独特的。
SomeClass.h
#ifndef SOME_CLASS_H
#define SOME_CLASS_H
class SomeClass {
private:
int m_x;
public:
SomeClass();
explicit SomeClass( x = 0 );
void setX( int x );
int getX() const;
private:
SomeClass( const SomeClass& c ); // Not Implemented - Copy Constructor
SomeClass& operator=( const SomeClass& c ); Not Implemented - Overloaded Operator=
}; // SomeClass
#endif // SOME_CLASS_H
SomeClass.cpp
#include "SomeClass.h"
// SomeClass() - Default Constructor
SomeClass::SomeClass() :
m_x( x ) {
} // SomeClass
// SomeClass() - Constructor With Default Parameter
SomeClass::SomeClass( int x ) :
m_x( x ) {
} // SomeClass
// setX()
void SomeClass::setX( int x ) {
m_x = x;
} // setX
// getX()
void SomeClass::getX() const {
return m_x;
} // getX
使用动态内存的旧方法
#include <iostream>
#include "SomeClass.h"
int main() {
// Single Dynamic Pointer
SomeClass* pSomeClass = nullptr;
pSomeClass = new SomeClass( 5 );
std::cout << pSomeClass->getX() << std::endl;
delete pSomeClass;
pSomeClass = nullptr;
// Dynamic Array
SomeClass* pSomeClasses = nullptr;
pSomeClasses = new SomeClasses[5](); // Default Constructor Called
for ( int i = 0; i < 5; i++ ) {
pSomeClasses[i]->setX( i * 10 );
std::cout << pSomeSomeClasses[i]->getX() << std::endl;
}
delete[] pSomeClasses;
pSomeClasses = nullptr;
return 0;
} // main
这里的问题是知道何时、何地以及为何删除内存;知道谁负责。如果您删除内存来管理它,而您的代码或库的用户认为您没有这样做,并且他们删除了它,那么就会出现问题,因为同一内存试图被删除两次。如果你让用户删除它,他们假设你删除了它,但他们没有删除,那么你就会遇到问题,并且存在内存泄漏。这就是智能指针派上用场的地方。
智能指针版
#include <iostream>
#include <memory>
#include <vector>
#include "SomeClass.h"
int main() {
// SHARED POINTERS
// Shared Pointers Are Used When Different Resources Need To Use The Same Memory Block
// There Are Different Methods To Create And Initialize Shared Pointers
auto sp1 = std::make_shared<SomeClass>( 10 );
std::shared_ptr<SomeClass> sp2( new SomeClass( 15 ) );
std::shared_ptr<SomeClass> sp3;
sp3 = std::make_shared<SomeClass>( 20 );
std::cout << "SP1: " << sp1->getX() << std::endl;
std::cout << "SP2: " << sp2->getX() << std::endl;
std::cout << "SP3: " << sp3->getX() << std::endl;
// Now If you Reach The Return Of Main; These Smart Pointers Will Decrement
// Their Reference Count & When It Reaches 0; Its Destructor Should Be
// Called Freeing All Memory. This Is Safe, But Not Guaranteed. You Can
// Release & Reset The Memory Your Self.
sp1.reset();
sp1 = nullptr;
sp2.reset();
sp2 = nullptr;
sp3.reset();
sp3 = nullptr;
// Need An Array Of Objects In Dynamic Memory?
std::vector<std::shared_ptr<SomeClass>> vSomeClasses;
vSomeClasses.push_back( std::make_shared<SomeClass>( 2 ) );
vSomeClasses.push_back( std::make_shared<SomeClass>( 4 ) );
vSomeClasses.push_back( std::make_shared<SomeClass>( 6 ) );
std::vector<std::shared_ptr<SomeClass>> vSomeClasses2;
vSomeClasses2.push_back( std::shared_ptr<SomeClass>( new SomeClass( 3 ) ) );
vSomeClasses2.push_back( std::shared_ptr<SomeClass>( new SomeClass( 5 ) ) );
vSomeClasses2.push_back( std::shared_ptr<SomeClass>( new SomeClass( 7 ) ) );
// UNIQUE POINTERS
// Unique Pointers Are Used When Only One Resource Has Sole Ownership.
// The Syntax Is The Same For Unique Pointers As For Shared Just Replace
// std::shared_ptr<SomeClass> with std::unique_ptr<SomeClass> &
// replace std::make_shared<SomeClass> with std::make_unique<SomeClass>
// As For Release Memory It Is Basically The Same
// The One Difference With Unique Is That It Has A Release Method Where Shared Does Not.
auto mp1 = std::make_unique<SomeClass>( 3 );
mp1.release();
mp1.reset();
mp1 = nullptr;
// Now You Can Also Do This:
// Create A Unique Pointer To An Array Of 5 Integers
auto p = make_unique<int[]>( 5 );
// Initialize The Array
for ( int i = 0; i < 5; i++ ) {
p[i] = i;
}
return 0;
} // main
这里是共享指针和唯一指针的参考链接
Adarsh Raj 的评论要求多维解决方案。
模板可能有助于本机数组的内存管理。
#include <iostream>
#include <cstring>
#define CLEANUP_TEST
#ifdef CLEANUP_TEST
long long deallocCount = 0;
#endif
/**
* Helper for Array<..>
* n-fold dereferencing of Element Type
* @tparam E
* @tparam n
*/
template <typename E, int n> struct Deref
{
typedef typename Deref<E,n-1>::T* T;
};
template <typename E> struct Deref<E,0>
{
typedef E T;
};
/**
* Helper for Array<..>
* Recursive Array Allocation
* @tparam E
* @tparam dim
* @tparam zeroInit
* @tparam cleanup
*/
template <typename E, int dim, bool zeroInit, bool cleanup> struct ArrayAllocator
{
static typename Deref<E,dim>::T alloc(int* dim0)
{
typename Deref<E,dim>::T res = new typename Deref<E,dim-1>::T[*dim0];
for (int i=0; i<*dim0; i++)
{
res[i] = ArrayAllocator<E,dim-1,zeroInit,cleanup>::alloc(dim0+1);
}
return res;
}
static void free(typename Deref<E,dim>::T p, int* dim0)
{
for (int i=0; i< *dim0; i++)
{
ArrayAllocator<E,dim-1,zeroInit,cleanup>::free(p[i], dim0+1);
}
}
};
template <typename E, bool zeroInit, bool cleanup> struct ArrayAllocator<E,1,zeroInit,cleanup>
{
static E* alloc(int* dim0)
{
E* res = new E[*dim0];
if (zeroInit)
{
std::memset(res, 0, (*dim0)*sizeof(E));
}
return res;
}
static void free(E* p, int* dim0)
{
if (cleanup)
{
#ifdef CLEANUP_TEST
deallocCount += *dim0;
#endif
std::memset(p, 0, (*dim0)*sizeof(E));
}
delete[] p;
}
};
/**
*
* @tparam E array element type
* @tparam dim array dimension
* @tparam zeroInit initialize array with zero, applicable for integral E, exclusively!
* @tparam cleanup set all elements to zero on release, applicable for integral E, exclusively!
* used case: sensitive data
*/
template <typename E, int dim, bool zeroInit=false, bool cleanup=false> class Array
{
public:
typedef typename Deref<E,dim>::T P;
private:
P p;
int bounds[dim];
public:
/**
* Constructor for undefined array
*/
Array()
: p(0)
{
}
/**
* Constructor with initial allocation
* @param bounds
*/
Array(int bounds[dim])
: p(0)
{
alloc(bounds);
}
/**
* Allocate array
* @param bounds
*/
void alloc(int bounds[dim])
{
if (p!=0)
{
throw std::runtime_error("Illegal Array State");
}
std::memcpy(this->bounds, bounds, sizeof(int[dim]));
p = ArrayAllocator<E,dim,zeroInit,cleanup>::alloc(bounds);
}
/**
* Functor for Array Access
* @return
*/
P operator ()()
{
return p;
}
/**
* Functor for Array Access, const version
* @return
*/
const P operator ()() const
{
return p;
}
/**
* Release array, involutoric
*/
void release()
{
if (p!=0)
{
ArrayAllocator<E,dim,zeroInit,cleanup>::free(p,bounds);
p = 0;
}
}
virtual ~Array()
{
release();
}
};
测试程序
static void assert(bool b)
{
if (!b)
{
throw std::runtime_error("Validation FAILED");
}
}
void test()
{
int bounds[] = {400,500,6};
Array<int,3, true, true> A0(bounds);
Array<int,3>::P p = A0();
for (int i=0; i<400; i++)
{
for (int j=0; j<500; j++)
{
for (int k=0; k<6; k++)
{
assert(p[i][j][k]==0);
}
}
}
for (int i=0; i<400; i++)
{
for (int j=0; j<500; j++)
{
for (int k=0; k<6; k++)
{
p[i][j][k] = i+j+k;
}
}
}
for (int i=0; i<400; i++)
{
for (int j=0; j<500; j++)
{
for (int k=0; k<6; k++)
{
assert (p[i][j][k] == i+j+k);
}
}
}
#ifdef CLEANUP_TEST
deallocCount = 0;
#endif
A0.release();
assert(A0()==0);
#ifdef CLEANUP_TEST
assert(deallocCount==400*500*6);
#endif
}
int main()
{
try
{
test();
std::cout << "OK" << std::endl;
}
catch (const std::exception& x)
{
std::cerr << x.what() << std::endl;
}
return 0;
}