下面的代码是否有内存泄露隐患

缘中人 2015-03-06 03:02:35
原文在 http://blogs.embarcadero.com/pawelglowacki/2014/06/04/40330
总感觉有内存没有释放的隐患,烦请大家分析指导

#include "System.Json.hpp"
#include "Data.FireDACJSONReflect.hpp"

TJSONObject* TServerMethods1::GetDepartmentNamesJSON()
{
FDQueryDepartmentNames->Close();

TFDJSONDataSets *ds = new TFDJSONDataSets();
TFDJSONDataSetsWriter::ListAdd(ds, FDQueryDepartmentNames);

TJSONObject *obj = new TJSONObject();
TFDJSONInterceptor::DataSetsToJSONObject(ds, obj);
return obj;
}
...全文
552 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
new_BCBER 2015-03-16
  • 打赏
  • 举报
回复
谢谢PPower 老师指教,受益匪浅,还要继续学习~
勉励前行 2015-03-15
  • 打赏
  • 举报
回复
#pragma startup 全局变量初始化后开始执行的函数,(main运行前) #pragma exit   全局变量析构前开始执行的函数 这是从C时代一直延续下来的东西。我有用过,略知一二: #pragma startup createContainer 33 后面这个33是优先级,不过对于CB来说,不要指定<64的优先级,那没用,因为0-63是给RTL内部使用的,它们总是先运行。如果未指定,默认的优先级是100,最大可设定为255。这里指定为33,我也不知道是否能插入到RTL内部运行,但一般不要指定<64的数,因为违反了约定,结果未明确定义。 当多个单元指定#pragma startup 函数时,优先级就代表了运行次序。0先运行。 #pragma exit  同样理解,只不过是程序退出前执行。  当有多个单元都定义有全局变量时,全局变量的初始化次序是未知的,也是不确定的,当全局变量间存在依赖时,可能会造成错误。#pragma startup 可以指定通过一个函数及优先级来解决这类初始化依赖问题。 1、当作为程序包或框架使用时,通过startup 及exit 初始化环境的操作得到保障,不会有用户忘记调用初始化环境函数的问题。 2、多个程序包时,初始化次序可以通过startup控制。 3、#pragma startup 与exit 的配合,解决了如何搭建与解除“应用程序的运行环境”这个问题。
new_BCBER 2015-03-15
  • 打赏
  • 举报
回复
本DEMO中底部的这种通过预编译语句来调用建立和释放函数的方法对我来说也很怪异,大师们给讲解一下其好处吧

//----------------------------------------------------------------------------
#include <fmx.h>
//
#include <tchar.h>
#include <stdio.h>
#include <memory>
#pragma hdrstop
#include "ServerMethodsUnit1.h"
#include "ServerContainerUnit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma classgroup "FMX.Controls.TControl"
#pragma resource "*.dfm"
TServerContainer1 *ServerContainer1;
TComponent *FModule;
TDSServer *FDSServer;
TDSAuthenticationManager *FDSAuthenticationManager;
//---------------------------------------------------------------------------
__fastcall TServerContainer1::TServerContainer1(TComponent* Owner)
	: TDataModule(Owner)
{
	FDSServer = DSServer1;
	FDSAuthenticationManager = DSAuthenticationManager1;
}
//---------------------------------------------------------------------------
__fastcall TServerContainer1::~TServerContainer1(void)
{
	FDSServer = NULL;
	FDSAuthenticationManager = NULL;
}
//----------------------------------------------------------------------------

void __fastcall TServerContainer1::DSServerClass1GetClass(TDSServerClass *DSServerClass,
          TPersistentClass &PersistentClass)
{
  	PersistentClass =  __classid(TServerMethods1);
}
//---------------------------------------------------------------------------
void __fastcall TServerContainer1::DSAuthenticationManager1UserAuthenticate(TObject *Sender,
          const UnicodeString Protocol, const UnicodeString Context, const UnicodeString User,
          const UnicodeString Password, bool &valid, TStrings *UserRoles)
{
	if (User == "")
	  valid = false;
	else
	  valid = true;

	if (User == "admin")
	  UserRoles->Add("admins");
}
//----------------------------------------------------------------------------
TDSServer *DSServer(void)
{
	return FDSServer;
}

TDSAuthenticationManager *DSAuthenticationManager(void)
{
	return FDSAuthenticationManager;
}

//---------------------------------------------------------------------------
static void createContainer()
{
	FModule = new TServerContainer1(NULL);
}
//---------------------------------------------------------------------------
static void freeContainer()
{
	free(FModule);
}
//---------------------------------------------------------------------------
#pragma startup createContainer 33  //编译优先级 // 开始之前建立
#pragma exit freeContainer 33                    // 退出之前释放

//freeWebModules表示在程序通过_exit退出之前,call名为 freeWebModules 这个函数。
//但是 freeWebModules 这个函数,必须是不携带参数,且不返回值的函数,即:void func(void);
// 33 这个优先级是可选的,但是必须在[64, 255]这个闭区间内。
// [1, 63]这个区间的优先级是用作ISO的startup和shutdown机制使用的,不要将优先级定义在此区间内。
// 如果不设定优先级,则默认设置为100。
晃晃悠悠 2015-03-14
  • 打赏
  • 举报
回复

#include "System.Json.hpp"
#include "Data.FireDACJSONReflect.hpp"

TJSONObject* TServerMethods1::GetDepartmentNamesJSON()
{
  FDQueryDepartmentNames->Close();

  TFDJSONDataSets *ds = new TFDJSONDataSets();
  TFDJSONDataSetsWriter::ListAdd(ds, FDQueryDepartmentNames);

  TJSONObject *obj = new TJSONObject();
  TFDJSONInterceptor::DataSetsToJSONObject(ds, obj);
  return obj;
}
虽然new 和delete不匹配,正常情况下也没问题的。 (正常情况是指client调用成功) TFDJSONInterceptor::DataSetsToJSONObject 内部应该会delete(free) 指针ds的。 而返回值 obj 会由datasnap销毁。
xjq2003 2015-03-12
  • 打赏
  • 举报
回复
GetDepartmentNamesJSON() 这个函数何时使用? 如果只调用有限几次,问题不大
new_BCBER 2015-03-12
  • 打赏
  • 举报
回复
RTTI远程调用,这是类声明.这几天学习这段,搞不太明白.谁来讲解一下,特别是JSON转换DATASET的那几个函数
class DECLSPEC_DRTTI TServerMethods1 : public TDataModule
{
__published:	// IDE-managed Components
	TFDStanStorageBinLink *FDStanStorageBinLink1;
	TFDQuery *FDQueryDepartment;
	TFDQuery *FDQueryDepartmentEmployees;
	TFDGUIxWaitCursor *FDGUIxWaitCursor1;
	TFDQuery *FDQueryDepartmentNames;
	TFDConnection *FDConnectionEMPLOYEE;
private:	// User declarations
public:		// User declarations
	__fastcall TServerMethods1(TComponent* Owner); 
	System::UnicodeString EchoString(System::UnicodeString value);
	System::UnicodeString  ReverseString(System::UnicodeString value);
	TJSONObject* GetDepartmentNamesJSON();
	TJSONObject* GetDepartmentEmployeesJSON(System::UnicodeString AID);
	void ApplyChangesDepartmentEmployeesJSON(TJSONObject* AJSONObject);
};
//---------------------------------------------------------------------------
extern PACKAGE TServerMethods1 *ServerMethods1;
//---------------------------------------------------------------------------


实现
//----------------------------------------------------------------------------
const System::String sEmployees = "Employees";
const System::String sDepartment = "Department";
//----------------------------------------------------------------------------
TJSONObject* TServerMethods1::GetDepartmentNamesJSON()
{
	FDQueryDepartmentNames->Close();

	TFDJSONDataSets *ds = new TFDJSONDataSets();
	TFDJSONDataSetsWriter::ListAdd(ds, FDQueryDepartmentNames);

	TJSONObject *obj = new TJSONObject();
	TFDJSONInterceptor::DataSetsToJSONObject(ds, obj);
	return obj;
}
//----------------------------------------------------------------------------
TJSONObject* TServerMethods1::GetDepartmentEmployeesJSON(System::UnicodeString AID)
{
  FDQueryDepartmentEmployees->Active = false;
  FDQueryDepartment->Active = false;
  FDQueryDepartment->Params->operator [](0)->Value = AID;
  FDQueryDepartmentEmployees->Params->operator [](0)->Value = AID;

  // Create dataset list
  TFDJSONDataSets *ds = new TFDJSONDataSets();
  // Add departments dataset
  TFDJSONDataSetsWriter::ListAdd(ds, sDepartment, FDQueryDepartment);
  // Add employees dataset
  TFDJSONDataSetsWriter::ListAdd(ds, sEmployees, FDQueryDepartmentEmployees);

  TJSONObject *obj = new TJSONObject();
  TFDJSONInterceptor::DataSetsToJSONObject(ds, obj);
  return obj;
}
//----------------------------------------------------------------------------
void TServerMethods1::ApplyChangesDepartmentEmployeesJSON(TJSONObject* AJSONObject)
{
  TFDJSONDeltas *LDeltas = new TFDJSONDeltas();
  TFDJSONInterceptor::JSONObjectToDataSets(AJSONObject, LDeltas);

  TFDJSONErrors *errs = new TFDJSONErrors();

  // Apply the department delta
  TFDJSONDeltasApplyUpdates::ListApplyUpdates(LDeltas, sDepartment, FDQueryDepartment->Command, errs);

  // If no errors, apply the employee delta
  if (errs->Count == 0) {
	TFDJSONDeltasApplyUpdates::ListApplyUpdates(LDeltas, sEmployees, FDQueryDepartmentEmployees->Command, errs);
  }

  // Raise an exception if any errors.
  if (errs->Count > 0) {
	 throw new Exception(errs->Strings->Text);
  }

}
//----------------------------------------------------------------------------


勉励前行 2015-03-11
  • 打赏
  • 举报
回复
1、这两个对象的删除时刻未定。不能当场就删除。 2、TJSONObject 中需要用到TFDJSONDataSets对象,也就是在TJSONObject 未析构前,TFDJSONDataSets不能删除。 3、函数返回一个TJSONObject 指针,由用户删除。   此时将 TFDJSONDataSets 的owner 设定为TJSONObject ,生命托管于TJSONObject 是一个选择,但该方式 TFDJSONDataSets 无法重用,所以我觉得 TFDJSONDataSets 使用引用计数方式管理生命会好些。该代码的问题在于需要通读TJSON代码才能知道该类使用哪种方式来管理内存。如果加上代码说明,这问题不算很大。对于我的建议是将与对象生命相关的部分独立出来,专门用一个函数,代码多一行(如:SetDataSetsOnwer( TFDJSONDataSets *)) 这样会让读者不困惑。当然如果所有的 TJSONObject 都自动管理着一堆子对象(即一个对象包括多个子对象),其最终代码可能就象原文那样只new 不delete了。 我没看TJSON类的代码,不知道猜得是否正确。
draculamx 2015-03-11
  • 打赏
  • 举报
回复
在函数里面 new 了两个对象,都没有使用 delete,是否有内存泄露,只有看函数外面是怎么处理的了。。最好改一下程序的结构,让new 和 delete 配对,或者使用成员变量做指针来接收这些 new 出来的对象
new_BCBER 2015-03-08
  • 打赏
  • 举报
回复
VCL对象在销毁时应该自动释放的.会随着服务对象生命期结束一同释放吧
new_BCBER 2015-03-08
  • 打赏
  • 举报
回复
delphi不存在这个问题?学习一下,也困惑传递方式..
缘中人 2015-03-06
  • 打赏
  • 举报
回复
由于是客户端、应用服务器模式,所以避免不了服务端返回数据给客户端
ccrun.com 2015-03-06
  • 打赏
  • 举报
回复
看起来这个 TJSONObject 对象好像没有释放,另外函数内部创建的 TJSONObject 对象,也不知道后续有没有释放。 我个人不太建议这样的编程方式,我比较趋向于 new 和 delete 配对。

602

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder VCL组件使用和开发
社区管理员
  • VCL组件使用和开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧