假设变量ps的类型 std::string*,能否判断ps0是否已经构造,答案是:不能。
例子1:
cpp
int main()
{
//分配3个std::string
std::string* ps = static_cast<std::string*>(::operator new(3 * sizeof(std::string)));
//构造第1个std::string
new (ps + 0) std::string("abc1");
//构造第2个std::string
new (ps + 1) std::string("abc2");
//现在ps[0] 与 ps[1] 可以用。
ps[0] = "for";
ps[1] = "int";
//ps[2] = "double"; //这里会出错,因为ps[2]未被构造
std::cout << ps[0] << "\n";
std::cout << ps[1] << "\n";
ps[0].~basic_string();
ps[1].~basic_string();
//ps[1].~basic_string(); 未被构造,也不能析构
::operator delete(ps);
}
输出:
例子2:
cpp
int main()
{
//分配3个std::string
std::string* ps = new std::string[3];
ps[0] = "for"; //不能构造,因为new内部已调用构造函数
ps[1] = "int"; //不能构造,因为new内部已调用构造函数
ps[2] = "double"; //不能构造,因为new内部已调用构造函数
std::cout << ps[0] << "\n";
std::cout << ps[1] << "\n";
std::cout << ps[2] << "\n";
delete[] ps;
}
输出:

下面语句,两次new会内存丢失吗?
cpp
string* pNew = static_cast<string*>(::operator new( 1 *sizeof(string)));
new (pNew+0) string(); //第一次
new new (pNew+0) string("abc"); //第二次new
答案是:会导致内存泄漏(严格说是资源泄漏),而且行为未定义。
具体原因:
-
第一次 placement new 已经构造了
string对象,分配了其内部资源(可能包括堆内存)。 -
第二次 placement new 在同一内存地址上再次构造新对象,会覆盖原有对象的内存,但不会调用原对象的析构函数 。因此第一次构造的
string对象内部的资源(如动态分配的字符数组)永远不会被释放,造成泄漏。 -
此外,在同一地址上连续 placement new 而不先析构原对象,是未定义行为。标准规定对象的生存期结束再构造新对象时,需要先显式调用析构函数。
正确做法:如果需要替换对象,应该先析构原对象,再 placement new:
cpp
pNew->~string();
new (pNew) string("abc");
下面是部份参考代码(完善中,只能参考):
cpp
/*
功能:在已有内存上构造单个对象。
注意:在标准 C++ 中,没有任何可移植的方式判断指针 T* pt 指向的内存位置是否已经
构造了对象。程序员必须手动跟踪哪些元素已构造。
正确叫法:placement new、定位构造。
原理:编译器在给定地址上直接调用构造函数,不涉及内存分配或格式识别。
创建时间:2026-06-13 最后一次修改时间:2026-06-14
*/
template<typename T, typename... Args>
T* construct_at(T* p, Args&&... args) {
/*
在标准 C++ 中,没有任何可移植的方式判断指针 T* pt 指向的内存位置是否已经构造了对象。
原因
(1) 没有"已构造标志":对象构造只是调用构造函数来初始化内存,但内存中并没有一个
内置的标记来指示该位置是否包含一个活动对象。
(2) 读取未构造对象是未定义行为:试图通过检查内存内容(例如读取 pt[0] 的字节)来判
断,本身就会触发未定义行为------因为访问尚未开始生命期的对象是标准禁止的。
(3) 平凡类型无法区分:对于 int 等平凡类型,构造与否就是内存中是否有有效值,但
一个未初始化的 int 可能恰好包含一个"看起来有效"的数值,无法区分。
(4) 实现可能有残留数据:即使内存尚未用于构造对象,其中可能残留之前的字节(例如
从 ::operator new 获得的内存未清零),但这些字节不代表一个活动对象。
*/
::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
++_construct_count; // 记录构造次数
return p;
}
/*
拷贝构造, 返回最后一个构造对象的下一个位置
创建时间:2026-06-13 最后一次修改时间:2026-06-14
*/
template<typename T, typename IterClass>
T* construct_at_list(T* p, const IterClass& itbegin, const IterClass& itEnd) {
T* current = p;
auto it = itbegin;
size_t constructed = 0;
try {
for (; it != itEnd; ++it, ++current, ++constructed) {
new (current) T(*it); // 拷贝构造
++_construct_count; // 记录构造次数(全局或类静态)
}
return current; // 返回最后一个构造对象的下一个位置
}
catch (...) {
// 异常回滚:析构已构造的对象
for (size_t i = 0; i < constructed; ++i) {
(p + i)->~T();
}
throw;
}
}
/*
记录析构次数
创建时间:2026-06-13 最后一次修改时间:2026-06-14
*/
template<typename T>
void destroy_at(T* p, const size_t& nCount = 1) {
if (p) {
for (size_t n = 0; n < nCount; ++n) {
p->~T();
}
_destroy_count += nCount; // 记录析构次数
}
}
/*
分配原始内存,不调用构造函数。
参数:
nCount 要分配的对象个数
pCopy 要拷贝的对象指针
nCopyCount 要拷贝的对象个数
nDefaultConstructionCount 要初始化对象的个数(如果有剩余)
new 运算符(new expression):例如 new T、new T(args)、new T[n]。它自动完成两件事:
(1) 调用 operator new 分配原始内存。
(2) 在分配的内存上调用构造函数(T::T(...))构造对象。
(3) operator new 分配的内存要用 operator delete 删除
::operator new:是一个函数,只负责分配原始内存(类似 malloc),不调用构造函数。
创建时间:2026-06-13 最后一次修改时间:2026-06-14
*/
template<class T>
T* allocate(
const size_t& nCount,
const T* pCopy = null,
const size_t& nCopyCount = 0) {
if (nCount == 0 || nCopyCount > nCount) {
throw "参数错误!";
}
if (sizeof(T) * nCount > _memory_allow_max) {
throw "超出最大允许申请的内存";
}
_obj_used += nCount;
_mem_used = _mem_used + sizeof(T) * nCount;
T* pNew = static_cast<T*>(::operator new(nCount * sizeof(T)));
/*
//复制数据
if (pCopy != null && nCopyCount != 0) {
for (size_t n = 0; n < nCopyCount; ++n) {
new (pNew + n) T(pCopy[n]);
}
}
//初始化未初始化的数据
if (nDefaultConstructionCount > 0) {
for (size_t n = nCopyCount; n < nCopyCount + nDefaultConstructionCount; ++n) {
new (pNew + n) T();
}
}
*/
construct_at_list(pNew, pCopy, pCopy + nCopyCount);
return pNew;
}
/*
分配nCount元素,并分配默认值
创建时间:2026-06-14 最后一次修改时间:2026-06-14
*/
template<class T>
T* allocate(const size_t& nCount, const T& defaultValue) {
T* ptNew = allocate<T>(nCount);
for (size_t n = 0; n < nCount; ++n) {
new (ptNew + n) T(defaultValue);
}
return ptNew;
}
/*
分配原始内存,不调用构造函数。
参数:
first 开始位置
nCopyCount 要拷贝的对象个数
new 运算符(new expression):例如 new T、new T(args)、new T[n]。它自动完成两件事:
(1) 调用 operator new 分配原始内存。
(2) 在分配的内存上调用构造函数(T::T(...))构造对象。
(3) operator new 分配的内存要用 operator delete 删除
::operator new:是一个函数,只负责分配原始内存(类似 malloc),不调用构造函数。
创建时间:2026-06-13 最后一次修改时间:2026-06-14
*/
template<class ItClass, class value_type = ItClass::value_type>
value_type* allocate(ItClass itBegin, ItClass itEnd) {
size_t nCount = std::distance(itBegin, itEnd);
value_type* ptNew = allocate<value_type>(nCount);
//ItClass it = itBegin;
//size_t n = 0;
//while (it != itEnd) {
// new (ptNew + n) value_type(*it);
// n++;
//}
construct_at_list(ptNew, itBegin, itEnd);
return ptNew;
}
/*
分配原始内存,不调用构造函数
参数:
nCount 要删除内存的个数
nDestructCount 要调用析构函数的个数(从0算起)
new 运算符(new expression):例如 new T、new T(args)、new T[n]。它自动完成两件事:
(1) 调用 operator new 分配原始内存。
(2) 在分配的内存上调用构造函数(T::T(...))构造对象。
(3) operator new 分配的内存要用 operator delete 删除
::operator new:是一个函数,只负责分配原始内存(类似 malloc),不调用构造函数。
allocate 英文:分配,分派;划拨;
deallocate 英文:去分配,解除分配,重新分配;
创建时间:2026-06-13 最后一次修改时间:2026-06-14
*/
template<class T>
void deallocate(T* p, const size_t& nCount, const size_t& nDestructCount = 0) noexcept {
if (nCount == 0 || p == null) return;
_obj_used -= nCount;
_mem_used -= sizeof(T) * nCount;
/*
deallocate 通常只负责释放原始内存,不应主动调用析构函数,因为:
调用者可能只构造了部分元素(例如 allocate 后只 placement new 了前几个对象)。
析构未构造的对象是未定义行为(UB)。
建议修改:将析构的职责完全交给调用者。deallocate 仅做两件事:
更新统计计数器。
调用 ::operator delete(p)。
*/
//for (size_t n = 0; n < nDestructCount; ++n)
// p[n].~T();
destroy_at(p, nDestructCount);
::operator delete(p);
}
_memory.h
cpp
/************************************************************
文件名 : _Memory.h
作者 : 李锋
功能 : 内存操作
创建时间 : 2016年7月6日
最后一次修改时间 : 2024年09月30日
**************************************************************/
#ifndef __MEMORY_H_
#define __MEMORY_H_
///////////////////////////////////////////////////////////////
#include "_macro.h"
///////////////////////////////////////////////////////////////
_LF_BEGIN_
///////////////////////////////////////////////////////////////
//
//内存操作类
static class _Memory {
public:
/// <summary>
/// 最大字符个数
/// </summary>
static const size_t _Maxchar = 100000000;
public:
//全局内存对象计数器
static size_t _obj_used;
static size_t _mem_used;
//充许最大内存数量
static size_t _memory_allow_max;
//记录构造函数次数
static size_t _construct_count;
//记录析构次数
static size_t _destroy_count;
public:
static inline size_t allow_max() { return _memory_allow_max; }
//内存使用量,字节
static inline size_t mem_used() { return _mem_used;}
//对象使用量
static inline size_t obj_used() { return _obj_used; }
public:
/// <summary>
/// 功能:分配内存。
///
/// 条款3:尽量以 new 和 delete 取代malloc 和 free
/// 分配内存,给对象分配内存不能用C语言的malloc函数, 因为 malloc函数不会调用用对象的
/// 构造函数,free函数不会调用对象的析构函数。
/// 条款5:使用相同形式的 new 和 delete
/// 游戏规则:如果你在调用 new 时使用了 [ ] ,则你必须在调用 delete 时也使用[] 。
/// 如果你在调用 new 的时候没有使用[],那么你也不应该在调用 delete 时使用[] 。
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
/// <param name="nCount">分配个数</param>
/// <returns></returns>
/// 创建时间: ????-??-?? 最后一次修改时间:2024-12-08
template<typename T> static T * New(const size_t& nCount, const bool& bZero = false)
{
if (nCount <= 0) return null;
if (sizeof(T) * nCount > _memory_allow_max)
throw "超出最大允许申请的内存";
_obj_used += nCount;
_mem_used = _mem_used + sizeof(T) * nCount;
//对于类类型(如 _Object),使用 new T[nCount] 或 new T[nCount]() 都会调用默认构造函数。
if (bZero) {
return new T[nCount]();
}else {
return new T[nCount];
}
}
/*
分配新内存,并拷贝数据。
创建时间: 2026-06-09 最后一次修改时间: 2026-06-09
*/
template<typename T> static T* NewCopy(const T* pData, const size_t& nCopyCount)
{
T* pNew = New<T>(nCopyCount);
for (size_t n = 0; n < nCopyCount; ++n) {pNew[n] = pData[n];}
return pNew;
}
/*
分配新内存,并拷贝数据。
nCopyCount: 要拷贝的个数
nBufferCount: 缓冲个数
创建时间: 2026-06-09 最后一次修改时间: 2026-06-09
*/
template<typename T> static T* NewCopy(const T* pData, const size_t& nCopyCount,
const size_t&nBufferCount){
T* pNew = New<T>(nCopyCount + nBufferCount);
for (size_t n = 0; n < nCopyCount; ++n) { pNew[n] = pData[n]; }
return pNew;
}
/// <summary>
/// 功能:释放内存,并把内存指针重置为0
///
/// 条款3:尽量以 new 和 delete 取代malloc 和 free
/// 分配内存,给对象分配内存不能用C语言的malloc函数, 因为 malloc函数不会调用用对象的
/// 构造函数,free函数不会调用对象的析构函数。
/// 条款5:使用相同形式的 new 和 delete
/// 游戏规则:如果你在调用 new 时使用了 [ ] ,则你必须在调用 delete 时也使用[] 。
/// 如果你在调用 new 的时候没有使用[],那么你也不应该在调用 delete 时使用[] 。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="pMemory"></param>
/// <param name="nCount"></param>
/// 创建时间:????-??-?? 最后一次修改时间:2025-06-24
template<typename T> static void Delete(T* pMemory, const size_t& nCount = 1)
{
_obj_used -= nCount;
_mem_used -= sizeof(T) * nCount;
delete[] pMemory;
}
/// <summary>
/// 这段代码实现了自定义的 mynew 和 mydelete 函数,用于替代标准的 new 和 delete 操作
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
/// 创建时间:2025-07-31 最后一次修改时间:2025-07-31
template<class T>
T* mynew(const T& value) {
size_t n = sizeof(T);
T* p = static_cast<T*>(malloc(n));
if (!p) {
throw std::bad_alloc(); // 或 return nullptr;
}
try {
new (p) T(value); // placement new
}
catch (...) {
free(p); // 如果构造失败,释放内存
throw; // 重新抛出异常
}
++_obj_used;
_mem_used += n;
return p;
}
/// <summary>
/// 这段代码实现了自定义的 mynew 和 mydelete 函数,用于替代标准的 new 和 delete 操作
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="p"></param>
/// 创建时间:2025-07-31 最后一次修改时间:2025-07-31
template<class T>
void mydelete(T* p) noexcept {
if (p) {
size_t n = sizeof(T);
p->~T();
free(p);
--_obj_used;
_mem_used -= n;
}
}
/*
功能:在已有内存上构造单个对象。
注意:在标准 C++ 中,没有任何可移植的方式判断指针 T* pt 指向的内存位置是否已经
构造了对象。程序员必须手动跟踪哪些元素已构造。
正确叫法:placement new、定位构造。
原理:编译器在给定地址上直接调用构造函数,不涉及内存分配或格式识别。
创建时间:2026-06-13 最后一次修改时间:2026-06-14
*/
template<typename T, typename... Args>
T* construct_at(T* p, Args&&... args) {
/*
在标准 C++ 中,没有任何可移植的方式判断指针 T* pt 指向的内存位置是否已经构造了对象。
原因
(1) 没有"已构造标志":对象构造只是调用构造函数来初始化内存,但内存中并没有一个
内置的标记来指示该位置是否包含一个活动对象。
(2) 读取未构造对象是未定义行为:试图通过检查内存内容(例如读取 pt[0] 的字节)来判
断,本身就会触发未定义行为------因为访问尚未开始生命期的对象是标准禁止的。
(3) 平凡类型无法区分:对于 int 等平凡类型,构造与否就是内存中是否有有效值,但
一个未初始化的 int 可能恰好包含一个"看起来有效"的数值,无法区分。
(4) 实现可能有残留数据:即使内存尚未用于构造对象,其中可能残留之前的字节(例如
从 ::operator new 获得的内存未清零),但这些字节不代表一个活动对象。
*/
::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
++_construct_count; // 记录构造次数
return p;
}
/*
拷贝构造, 返回最后一个构造对象的下一个位置
创建时间:2026-06-13 最后一次修改时间:2026-06-14
*/
template<typename T, typename IterClass>
T* construct_at_list(T* p, const IterClass& itbegin, const IterClass& itEnd) {
T* current = p;
auto it = itbegin;
size_t constructed = 0;
try {
for (; it != itEnd; ++it, ++current, ++constructed) {
new (current) T(*it); // 拷贝构造
++_construct_count; // 记录构造次数(全局或类静态)
}
return current; // 返回最后一个构造对象的下一个位置
}
catch (...) {
// 异常回滚:析构已构造的对象
for (size_t i = 0; i < constructed; ++i) {
(p + i)->~T();
}
throw;
}
}
/*
记录析构次数
创建时间:2026-06-13 最后一次修改时间:2026-06-14
*/
template<typename T>
void destroy_at(T* p, const size_t& nCount = 1) {
if (p) {
for (size_t n = 0; n < nCount; ++n) {
p->~T();
}
_destroy_count += nCount; // 记录析构次数
}
}
/*
分配原始内存,不调用构造函数。
参数:
nCount 要分配的对象个数
pCopy 要拷贝的对象指针
nCopyCount 要拷贝的对象个数
nDefaultConstructionCount 要初始化对象的个数(如果有剩余)
new 运算符(new expression):例如 new T、new T(args)、new T[n]。它自动完成两件事:
(1) 调用 operator new 分配原始内存。
(2) 在分配的内存上调用构造函数(T::T(...))构造对象。
(3) operator new 分配的内存要用 operator delete 删除
::operator new:是一个函数,只负责分配原始内存(类似 malloc),不调用构造函数。
创建时间:2026-06-13 最后一次修改时间:2026-06-14
*/
template<class T>
T* allocate(
const size_t& nCount,
const T* pCopy = null,
const size_t& nCopyCount = 0) {
if (nCount == 0 || nCopyCount > nCount) {
throw "参数错误!";
}
if (sizeof(T) * nCount > _memory_allow_max) {
throw "超出最大允许申请的内存";
}
_obj_used += nCount;
_mem_used = _mem_used + sizeof(T) * nCount;
T* pNew = static_cast<T*>(::operator new(nCount * sizeof(T)));
/*
//复制数据
if (pCopy != null && nCopyCount != 0) {
for (size_t n = 0; n < nCopyCount; ++n) {
new (pNew + n) T(pCopy[n]);
}
}
//初始化未初始化的数据
if (nDefaultConstructionCount > 0) {
for (size_t n = nCopyCount; n < nCopyCount + nDefaultConstructionCount; ++n) {
new (pNew + n) T();
}
}
*/
construct_at_list(pNew, pCopy, pCopy + nCopyCount);
return pNew;
}
/*
分配nCount元素,并分配默认值
创建时间:2026-06-14 最后一次修改时间:2026-06-14
*/
template<class T>
T* allocate(const size_t& nCount, const T& defaultValue) {
T* ptNew = allocate<T>(nCount);
for (size_t n = 0; n < nCount; ++n) {
new (ptNew + n) T(defaultValue);
}
return ptNew;
}
/*
分配原始内存,不调用构造函数。
参数:
first 开始位置
nCopyCount 要拷贝的对象个数
new 运算符(new expression):例如 new T、new T(args)、new T[n]。它自动完成两件事:
(1) 调用 operator new 分配原始内存。
(2) 在分配的内存上调用构造函数(T::T(...))构造对象。
(3) operator new 分配的内存要用 operator delete 删除
::operator new:是一个函数,只负责分配原始内存(类似 malloc),不调用构造函数。
创建时间:2026-06-13 最后一次修改时间:2026-06-14
*/
template<class ItClass, class value_type = ItClass::value_type>
value_type* allocate(ItClass itBegin, ItClass itEnd) {
size_t nCount = std::distance(itBegin, itEnd);
value_type* ptNew = allocate<value_type>(nCount);
//ItClass it = itBegin;
//size_t n = 0;
//while (it != itEnd) {
// new (ptNew + n) value_type(*it);
// n++;
//}
construct_at_list(ptNew, itBegin, itEnd);
return ptNew;
}
/*
分配原始内存,不调用构造函数
参数:
nCount 要删除内存的个数
nDestructCount 要调用析构函数的个数(从0算起)
new 运算符(new expression):例如 new T、new T(args)、new T[n]。它自动完成两件事:
(1) 调用 operator new 分配原始内存。
(2) 在分配的内存上调用构造函数(T::T(...))构造对象。
(3) operator new 分配的内存要用 operator delete 删除
::operator new:是一个函数,只负责分配原始内存(类似 malloc),不调用构造函数。
allocate 英文:分配,分派;划拨;
deallocate 英文:去分配,解除分配,重新分配;
创建时间:2026-06-13 最后一次修改时间:2026-06-14
*/
template<class T>
void deallocate(T* p, const size_t& nCount, const size_t& nDestructCount = 0) noexcept {
if (nCount == 0 || p == null) return;
_obj_used -= nCount;
_mem_used -= sizeof(T) * nCount;
/*
deallocate 通常只负责释放原始内存,不应主动调用析构函数,因为:
调用者可能只构造了部分元素(例如 allocate 后只 placement new 了前几个对象)。
析构未构造的对象是未定义行为(UB)。
建议修改:将析构的职责完全交给调用者。deallocate 仅做两件事:
更新统计计数器。
调用 ::operator delete(p)。
*/
//for (size_t n = 0; n < nDestructCount; ++n)
// p[n].~T();
destroy_at(p, nDestructCount);
::operator delete(p);
}
/// <summary>
/// 返回一个二维数组 nRows * nColoumns 二维数组,给它分配内存,
/// 并把每个元素初始化
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="x"></param>
/// <param name="numberofRows"></param>
/// <param name="numberOfColumns"></param>
/// <returns></returns>
/// 创建时间: 2024-10-06 最后一修改时间:2024-10-06
template<class T>
static T** New2dArray(const size_t& nRows, const size_t& nColumns)
{
T** x;
try {
//创建行指针
x = New<T*>(nRows);
//为每一行分配空间,每行有 numberOfColumns 个元素
for (size_t n = 0; n < nRows; n++)
x[n] = New<T>(nColumns, true);
return x;
}
catch (std::bad_alloc) { return null; }
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="x"></param>
/// <param name="nRows"></param>
/// <param name="nColumns"></param>
/// 创建时间: 2024-10-06 最后一修改时间:2024-10-06
template<class T>
static void Delete2dArray(T** x, const size_t& nRows, const size_t& nColumns)
{
//为每一行分配空间,每行有 numberOfColumns 个元素
for (size_t n = 0; n < nRows; n++)
Delete<T>(x[n], nColumns);
Delete<T*>(x, nRows);
}
/// <summary>
/// 可以构造任意对象的函数
/// </summary>
/// <typeparam name="MyClass">要转换对象的类型</typeparam>
/// <typeparam name="...MyClassConstructorParameterTypes">转换对象的构造函数参数类型</typeparam>
/// <param name="...MyClassConstructorParameters">转换对象的构造函数参数</param>
/// <returns>返回一个对象</returns>
/// 创建时间: 2024-09-23 最后一次修改时间:2024-09-23
template <class MyClass, typename... MyClassConstructorParameterTypes>
MyClass ConverTo(MyClassConstructorParameterTypes&&... MyClassConstructorParameters)
{
return MyClass(
std::forward<MyClassConstructorParameterTypes>(MyClassConstructorParameters)...);
}
/// <summary>
/// 直接构建一个新的MyClass,并返回它的一个指针。(好处免去初始化)
/// 用法例子:
///
/// list<int>* pl = NewEmplace<list<int>>(5,10); //申请一个列表内存指针(5个元素都是10的列表)
/// delete[] pl; //删除内存对象,分配时用new[]分配的
/// </summary>
/// <typeparam name="MyClass"></typeparam>
/// <typeparam name="...MyClassConstructorParameterTypes"></typeparam>
/// <param name="...MyClassConstructorParameters"></param>
/// <returns></returns>
/// 创建时间: 2024-10-01 最后一次修改时间:2024-10-01
template<typename MyClass, typename... MyClassConstructorParameterTypes>
static MyClass* NewEmplace(MyClassConstructorParameterTypes&&... MyClassConstructorParameters)
{
_obj_used += 1;
_mem_used = _mem_used + sizeof(MyClass);
/*
//不能用 delete[] 删除
return new MyClass(
std::forward<MyClassConstructorParameterTypes>(MyClassConstructorParameters)...);
*/
/*
list<int> il = { 1,2,3 };
std::list<int>* p2 = new std::list<int>[1] {il};
*/
//delete[] pl; //删除内存对象,分配时用new[]分配的
return new MyClass[1]
{
MyClass(
std::forward<MyClassConstructorParameterTypes>(MyClassConstructorParameters)...)
};
}
/// <summary>
/// 不改变原有数据,把内存段区间 [begin,pend) 向后移动nCount位,后面的
/// 数据会pend后面会覆盖nCount-1个,包括pend就是nCount个,如果bFilling
/// 为True,则用相应的pFilling所指的数据填充空出来的内存。
/// 例:
/// _string s = "sss123 www"; //中间3个空格
/// MoveBack(s.begin(), s.begin() + 6, 3, true, s.end() - 3);
/// 结果:s=wwwsss123www
///
/// 注意:(1) pFilling 与 pbegin,pend,不能在同一区域的内存块中。
/// 注意:(2) 填空的字符长度要与空出来的字符长度一致。
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
/// <param name="pbegin">开始位置</param>
/// <param name="pend">结束位置</param>
/// <param name="nCount">移运个数</param>
/// <param name="bFilling">是否填充</param>
/// <param name="pFilling">指向填充数据的指针</param>
/// <returns></returns>
/// 创建时间:2024-10-03 最后一次修改时间:2024-10-03 (已测试)
template<class T>
static T* MoveBack(T* pbegin, T* pend, const size_t& nCount,
const bool& bFilling = false, const T* pFilling = null){
assert(pend >= pbegin);
for (size_t n = 0; n < pend - pbegin; ++n) {
*(pend + nCount - 1 - n) = *(pend - 1 - n);
}
if (bFilling && pFilling) { //检查bFilling不能在区间[pbegin,pend + nCount)中
assert(pFilling < pbegin || pFilling >= pend + nCount);
for (size_t n = 0; n < nCount; ++n) {
*(pbegin + n) = *(pFilling + n);
}
}
return pbegin;
}
/// <summary>
/// 不改变原有数据,把内存段区间 [begin,pend) 向前移动nCount位,
/// pbegin前面的会会覆盖nCount个,如果bFilling为True,则用相应
/// 的pFilling所指的数据填充空出来的内存。
/// 例:
/// _string s = " sss123www";
/// MoveFont(s.begin(), s.begin() + 6, 3, true, s.end() - 3);
/// 结果:s=wwwsss123www
///
/// 注意:pFilling 与 pbegin,pend,不能在同一区域的内存块中。
///
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
/// <param name="pbegin">开始位置</param>
/// <param name="pend">结束位置</param>
/// <param name="nCount">移运个数</param>
/// <param name="bFilling">是否填充</param>
/// <param name="pFilling">指向填充数据的指针</param>
/// <returns></returns>
/// 创建时间:2024-10-03 最后一次修改时间:2024-10-03 (已测试)
template<class T>
static T* MoveFront(T* pbegin, T* pend, const size_t& nCount,
const bool& bFilling = false, const T* pFilling = null) {
assert(pend >= pbegin);
for (size_t n = 0; n < pend - pbegin; ++n) {
*(pbegin - nCount + n) = *(pbegin + n);
}
if (bFilling && pFilling) { //检查bFilling不能在区间[pbegin,pend + nCount)中
assert(pFilling < pbegin - nCount || pFilling >= pend);
for (size_t n = 0; n < nCount; ++n) {
*(pbegin - nCount + n) = *(pFilling + n);
}
}
return pbegin;
}
template<class IterClass, class ValueType>
static const IterClass MoveBackIter(const IterClass& itbegin, const IterClass& itend,
const size_t& nCount,const bool& bFilling = false,
const ValueType* pFilling = null){
//assert(itend >= itbegin); //可能很多迭代器不支持
for (size_t n = 0; n < itend - itbegin; ++n) {
*(itend + nCount - 1 - n) = *(itend - 1 - n);
}
if (bFilling && pFilling) { //检查bFilling不能在区间[pbegin,pend + nCount)中
//可能很多迭代器不支持
//assert(pFilling < itbegin || pFilling > itend + nCount);
for (size_t n = 0; n < nCount; ++n) {
*(itbegin + n) = *(pFilling + n);
}
}
return itbegin;
}
/// <summary>
/// 判断pt是否指向区块内存[pbegin,pend)。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="pbegin"></param>
/// <param name="pend"></param>
/// <param name="pt"></param>
/// <returns></returns>
/// 创建时间:2024-10-04 最后一次修改时间:2024-10-04
template<class T>
static bool isPointsToTheSameMemoryArea(const T* pbegin, const T* pend, const T* pt)
{
return pt >= pbegin && pt < pend;
}
/// <summary>
/// 设置内存的值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="pMem"></param>
/// <param name="nCount"></param>
/// <param name="rDefaultValue"></param>
/// <returns></returns>
template<typename T> static T *Set(T *pMem,const size_t nCount, const T &rDefaultValue)
{
assert(pMem != null);
for (size_t n = 0; n < nCount; ++n)
*(pMem + n) = rDefaultValue;
return pMem;
}
/// <summary>
/// 内存内存
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="pDestination">指向目标内存指针</param>
/// <param name="pSource">指向需要拷贝的内存</param>
/// <param name="nCount">需要拷贝的内存个数</param>
/// <returns>返回指向目标内存的指针</returns>
/// 创建时间: ????-??-??(2020-01-01) 最后一次修改时间:2024-05-04
template<typename T> static T *Copy(T *pDestination, const T *pSource, const size_t& nCount)
{
//assert(nCount != 0 && pDestination != null && pSource != null);
//assert(pDestination != null && pSource != null); //nCount 可以允许为0。
for (size_t n = 0; n < nCount; ++n){
pDestination[n] = pSource[n];
}
return pDestination;
}
/// <summary>
/// 在两种不同的数据之间拷贝
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <param name="pDestination"></param>
/// <param name="pSource"></param>
/// <param name="nCount"></param>
/// <returns></returns>
/// 创建时间: 2025-02-13 最后一次修改时间:2025-02-13
template<class T1,class T2>
static T1* Copy(T1* pDestination, const T2* pSource, const size_t& nCount) {
for (int i = 0; i < nCount; ++i) {
pDestination[i] = pSource[i];
}
return pDestination;
}
/// <summary>
/// 比较丙段内存是否相等,相当于strcmp
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="pt1"></param>
/// <param name="pt2"></param>
/// <param name="nCount"></param>
/// <returns></returns>
/// 创建时间: 2025-03-13 最后一次修改时间:2025-03-13
template<class T>
static int Cmp(const T* pt1, const T* pt2, const size_t nCount) {
for (size_t n = 0; n < nCount; ++n) {
int diff = pt1[n] - pt2[n];
if (diff != 0) return diff;
}
return 0; //完全相等
}
} m;
/// <summary>
/// 内存管理,内存自动释放
/// </summary>
/// <typeparam name="T"></typeparam>
/// 创建时间: ????-??-?? 最后一次修改时间:2025-02-09
template<typename T = char>
class _Mem
{
private:
T* _pData = null; //指针,指向第一个元素
size_t _nElementCount = 0; //无素个数
size_t _nBufferCount = 0; //剩余缓冲区无素个数
size_t _nAutoBufferCount = 0; //自动设置缓冲次数的计数器
bool _isManaged = false; //是否被托管的
public:
/// <summary>
/// 指向 以 T 为单位的内存指针。
/// </summary>
inline T* data() const { return _pData; }
inline T* data() { return _pData; }
/// <summary>
/// 获取以 T 为单位有效数据内存长度。
/// </summary>
inline size_t elementCount() const { return _nElementCount; };
inline size_t bufferCount()const { return _nBufferCount; }
/// <summary>
/// 获取以 T 为单位总共分配的元素个数。
/// </summary>
/// <returns></returns>
inline size_t allElementCount()const { return _nElementCount + _nBufferCount; }
inline size_t memorySize()const { return allElementCount() * sizeof(T); }
/// <summary>
/// 重新分配内存
/// </summary>
/// <param name="nCount"></param>
/// 创建时间: 2023-09-22 最后一次修改时间:2023-09-22
inline void reallocate(const size_t& nBuffer)
{
free();
if (_isManaged) {
_pData = _Memory::New<T>(nBuffer);
_nElementCount = 0;
_nBufferCount = nBuffer;
_nAutoBufferCount = 0;
}
}
/// <summary>
/// 释放内存
/// </summary>
/// 创建时间: 2023-09-22 最后一次修改时间:2023-09-22
inline void free()
{
/*
T* _pData; //指针,指向第一个元素
size_t _nCount; //无素个数
size_t _nBufferCount; //剩余缓冲区无素个数
size_t _nAutoBufferCount = 0; //自动设置缓冲次数的计数器
bool _isManaged = false; //是否被托管的
*/
if (!_isManaged)
{
_Memory::Delete<T>(_pData, allElementCount());
_pData = null;
_nElementCount = 0;
_nBufferCount = 0;
_nAutoBufferCount = 0;
}
}
/// <summary>
/// 构造函数,分配内存
/// </summary>
/// <param name="nAllLength"></param>
inline _Mem(const size_t& nBuffer = 0)
{
if (nBuffer > 0){ setBuffer(nBuffer); }
}
/// <summary>
///
/// </summary>
/// <param name="pstr"></param>
/// 创建时间: 2025-02-09 最后一次修改时间:2025-02-09
inline _Mem(const char* pstr) {
assert(pstr != 0);
_nElementCount = strlen(pstr);
_nBufferCount = 1;
_pData = _Memory::New<T>(_nElementCount + _nBufferCount, false);
for (int i = 0; i <= _nElementCount; ++i) {
_pData[i] = pstr[i];
}
}
/// <summary>
/// 拷贝构造
/// </summary>
/// 创建时间: 2023-05-10 最后一次修改时间:2023-05-10
inline _Mem(const _Mem<T>& m)
{
/*
T* _pData; //指针,指向第一个元素
size_t _nCount; //无素个数
size_t _nBufferCount; //剩余缓冲区无素个数
size_t _nAutoBufferCount = 0; //自动设置缓冲次数的计数器
bool _isManaged = false; //是否被托管的
*/
if (m._isManaged) { throw "错误:被托管内存无法拷贝。"; }
if (this != &m) {
_nElementCount = m._nElementCount;
_nBufferCount = m._nBufferCount;
_nAutoBufferCount = m._nAutoBufferCount;
_pData = _Memory::New<T>(_nElementCount + _nBufferCount);
_Memory::Copy(_pData, m._pData, _nElementCount + _nBufferCount);
}
//_cout << _t("inline _Mem(const _Mem<T>& m)\n");
}
/// <summary>
/// 把有效数据的后一位数据进行初始化,如果是数字,则会自动初始化0。
/// </summary>
inline void zeroEnd() {
if (_isManaged) { throw "错误:被托管内存数据不能改动!"; }
if (_nBufferCount > 0) _pData[_nElementCount] = T();
}
/// <summary>
/// 初始化所有内存
/// </summary>
/// 创建时间: 2023-09-05 最后一次修改时间:2023-09-05
inline void zeroAll()
{
if (_isManaged) { throw "错误:被托管内存数据不能改动!";}
for (size_t i = 0; i < allElementCount(); ++i)
{
*(_pData + i) = T();
}
}
inline void zeroBuffer() {
for (size_t n = _nElementCount; n < _nBufferCount + _nElementCount; ++n) {
_pData[n] = 0;
}
}
/// <summary>
/// 设置以 T 为单位的内存长度,并把有效数据的后一位数据进行初始化,如果是数字,则会自动初始化0。
/// </summary>
/// 创建时间: 2023-09-05 最后一次修改时间:2025-02-09
void setElementCount(const size_t& nNewElementCount)
{
if (_isManaged) { throw "错误:被托管内存数据不能改动!";}
size_t nAll = allElementCount();
assert(nNewElementCount <= nAll);
_nElementCount = nNewElementCount;
_nBufferCount = nAll - _nElementCount;
zeroEnd();
}
/// <summary>
/// 设置新的缓冲数量,并添加一段新数据。
/// 原则:
/// 先拷贝所有数据,再删除旧数据,因为
/// 当添加的数据是指向旧数据时,会出现问题。
/// </summary>
/// <param name="nNewBuffer"></param>
/// <param name="pAdd"></param>
/// <param name=""></param>
/// <returns></returns>
/// 创建时间: 2025-02-09 最后一次修改时间:2025-02-09
size_t setBuffer(const size_t& nNewBuffer, const T* pAdd = null,
const size_t& nAddCount = 0) {
if (_isManaged) { throw "错误:被托管内存数据不能改动!";}
//当缓冲足够保存新数据时
if (_nBufferCount > nAddCount + nNewBuffer) {
for (int i = 0; i < nAddCount; ++i) {
_pData[_nElementCount + i] = *(pAdd + i);
}
_nElementCount += nAddCount;
_nBufferCount -= nAddCount;
return _nBufferCount;
}
//旧内存长度
size_t nOld = _nElementCount + _nBufferCount;
T* pt = null;
if (pAdd != null && nAddCount != 0) {
//分配新内存
pt = _Memory::New<T>(_nElementCount + nNewBuffer + nAddCount);
if(_pData != null){
//拷贝旧数据
_Memory::Copy(pt, _pData, _nElementCount);
//拷贝添加的数据
_Memory::Copy(pt + _nElementCount, pAdd, nAddCount);
_nElementCount = _nElementCount + nAddCount;
}else {
//拷贝添加的数据
_Memory::Copy(pt, pAdd, nAddCount);
_nElementCount = nAddCount;
}
}else { //元素个数未改变
if (_pData != null) {
//分配新内存
pt = _Memory::New<T>(_nElementCount + nNewBuffer);
//拷贝旧数据
_Memory::Copy(pt, _pData, _nElementCount);
}
else {
//分配新内存
pt = _Memory::New<T>(nNewBuffer);
}
}
//设置新的缓冲数量
_nBufferCount = nNewBuffer;
//删除旧内存
_Memory::Delete<T>(_pData, nOld);
//指向新内存
_pData = pt;
return _nBufferCount;
}
/// <summary>
/// 添加一串元素,要考虑pAdd与_pData指向同一位置,或同一段内存。
/// </summary>
/// <param name="tValue"></param>
/// 创建时间: 2025-02-09 最后一次修改时间:2025-02-09
inline void add(const T* pAdd, const size_t& nAdd) {
if (_nBufferCount < nAdd) {
++_nAutoBufferCount;
size_t n = 2 << _nAutoBufferCount;
setBuffer(n, pAdd, nAdd);
}
else {
setBuffer(0, pAdd, nAdd);
}
}
/// <summary>
/// 添加一个元素
/// </summary>
/// <param name="tValue"></param>
/// 创建时间: 2025-02-09 最后一次修改时间:2025-02-09
inline void add(const T& tValue) { add(&tValue, 1); }
/// <summary>
/// 当bManaged为True时,内存被托管,释放对象时
/// 不会自动释放内存。
/// </summary>
/// <param name="bManaged"></param>
/// 创建时间: 2025-02-09 最后一次修改时间:2025-02-09
inline void setManaged(const bool& bManaged) { this->_isManaged = bManaged; }
/// <summary>
///
/// </summary>
/// 创建时间: 2025-02-14 最后一次修改时间:2025-02-14
inline operator T* () { return _pData; }
/// <summary>
/// 析构函数,释放内存。
/// </summary>
~_Mem()
{
free();
}
/// <summary>
/// 放弃对象当前使用的内存,可能内存已托管给别的对象,
/// 重新初始化当前对象,除非内存给其它对象托管,否则不要调用这个函数。
/// </summary>
/// 创建时间:2026-05-04 最后一次修改时间:2026-05-04
inline void giveUpMem()
{
this->setManaged(true);
}
};
///////////////////////////////////////////////////////////////
_LF_END_
///////////////////////////////////////////////////////////////
#endif //_memory__H_
///////////////////////////////////////////////////////////////