我有以下类叫做DATA。
enum DATATYPE{DATATYPE_CONSTANT=0, DATATYPE_NUMBER,DATATYPE_STRING, DATATYPE_MATRIX, DATATYPE_OBJECT};
struct DATA //A Data container for the variable
{
DATA(DATATYPE type,int row=0,int col=0)
{
m_str=0;m_number=0;
m_DataType=type;
if(type==DATATYPE_NUMBER) m_number=new double;
if(type==DATATYPE_STRING) m_str=new string("");
cout<<"In constructor"<<endl;
//if(type==DATATYPE_MATRIX) m_matrix= new MatrixXd(row,col);
}
~DATA()
{
if(m_str) m_str->clear();
if(m_number) {delete m_number; m_number=0;}
std::cout<<"In Destructor"<<std::endl;
//if(m_matrix) {delete m_matrix; m_matrix=0;}
}
DATA(const DATA& other)
{
m_number=other.m_number;
m_str=other.m_str;
m_DataType=other.m_DataType;
cout<<"In copy constructor"<<endl;
}
DATA& operator=(const DATA& other)
{
m_number=other.m_number;
m_str=other.m_str;
m_DataType=other.m_DataType;
cout<<"In operator="<<endl;
return *this;
}
DATATYPE GetType()
{
return m_DataType;
}
double* GetNumber()
{
return m_number;
}
void SetNumber(const double& val){*m_number=val;}
string* GetString()
{
return m_str;
}
private:
DATATYPE m_DataType;
string* m_str;
//MatrixXd* m_matrix;
double* m_number;
};
我有以下测试:
DATA GetData();
int main()
{
cout<<"Before GetData call"<<endl;
DATA dat=GetData();
//DATA dat2=dat;
cout<<*(dat.GetNumber())<<endl;
cout<<"After Get Data call"<<endl;
cout << "Exiting main" << endl;
return 0;
}
DATA GetData()
{
cout<<"In Get Data"<<endl;
DATA ret(DATATYPE_NUMBER);
double d=5;
ret.SetNumber(d);
cout<<"Exiting GetData"<<endl;
return ret;
}
运行测试后,输出为:
在GetData调用之前
获取数据
在构造函数
中退出GetData
5
获取数据通话后
退出主要
在析构函数
中
我有以下问题:
当我调用DATA dat=GetData();
时,它既不调用构造函数,也不调用构造函数,也不调用运算符。如何构造dat对象。从GetData
返回时,编译器究竟做了什么?
对于DATA
结构或一般聚合数据类型,使用new
初始化成员变量总是一个好主意吗?初始化时,成员变量会发生什么变化DATA *d=new DATA(DATATYPE_NUMBER)
?内存泄漏是否更容易出错?
答案 0 :(得分:1)
问题1
当我调用DATA dat=GetData();
时,它既不调用构造函数,也不调用构造函数,也不调用运算符。如何构造dat对象。从GetData
返回时,编译器究竟做了什么?
回答这是返回值优化(RVO)的结果。您可以阅读有关他们的更多信息here。
在g ++中,您可以使用标记-fno-elide-constructors
禁用RVO。如果您使用代码执行此操作,您将看到来自复制构造函数的消息。
问题2
对于DATA
结构,或者通常的聚合数据类型,使用new初始化成员变量总是一个好主意吗?初始化时,成员变量会发生什么变化DATA *d=new DATA(DATATYPE_NUMBER)
?内存泄漏是否容易出错?
<强>答案强>
有三个问题。
回答2.1
该问题的答案是&#34;取决于您的应用程序&#34;。对于某些人来说,将对象作为成员数据是有意义的,而对于其他人来说,指向对象是有意义的。当您使用指向对象的指针时,您必须遵循已成为Rule of Three的Rule of Five in C++11。
回答2.2
成员变量的初始化与使用时一样:
Data d = DATA(DATATYPE_NUMBER);
回答2.3
使用动态内存有好处,但它也有其缺点。无论何时使用动态内存分配,您都会遇到更容易出错的代码。你必须担心其潜在的不良副作用:
答案 1 :(得分:1)
当我调用DATA dat = GetData()时;它既不调用构造函数,也不复制构造函数,也不调用运算符如何构造dat对象。从GetData返回时编译器究竟做了什么?
等于运算符:即使它看起来像你正在分配,但事实并非如此。语法T t = u;
不包含任何赋值,而是复制构造。
构造函数:在函数内部调用构造函数,然后返回 copy , copy 依次复制< / em>在目标对象上。除非它不是。该语言允许 copy-elision ,这意味着允许编译器通过将三个对象(ret
放置在函数内,返回的对象和dat
在main内部来删除副本)在同一个记忆位置。
我不确定确切的细节有多重要或有多大帮助,但在大多数ABI中(据我所知),一个按值返回的函数,一个对象被编译器转换为一个函数,该函数获取指向所在位置的指针对象将会存在。
T f(int x) {
T tmp(x);
return tmp;
}
int main() {
T t = f(1);
}
转化为:
void f(void *__ret, int x) {
new (__ret) T(x); // constructor call
return; // return does not *copy*
}
int main() {
[[uninitialized]] T t; // space is reserved, no construction
f(&t, 1);
}
字面意思是copy-elision函数,f
在返回值(参数)之上创建了tmp
对象,main
中的调用者放置了t
和f
在同一内存位置的返回值。
你告诉我。但在回答之前,请注意您的对于DATA结构,或者一般的聚合数据类型,使用new初始化成员变量总是一个好主意吗?初始化时成员变量会发生什么,说DATA * d = new DATA(DATATYPE_NUMBER)?内存泄漏是否容易出错?
DATA
类型有内存泄漏。
答案 2 :(得分:0)
使构造函数显式化并删除DATA(enum,int,int)上的默认参数。当GetData()使用单个参数构造对象时,您最有可能获得编译器生成的默认构造函数。
你可以通过输入m_str&amp;来节省内存。联合中的m_number而不是单独的成员变量:
DATA {
...
union U {
string* m_string;
double* m_number;
}
DATATYPE m_DataType;
U m_data;
}
当成员很大或者为了提高性能而构建起来时,使用成员指针既美观又常见。但你必须采取额外的措施,以避免内存泄漏。 OTOH,如果成员很小,常规成员变量的便利性通常是最好的。