如何解决为什么在另一个 ctor 中调用 ctor 会出错?
这是一个演示代码片段(https://godbolt.org/z/31Tq3r):
#include<iostream>
class Ctx
{
public:
enum RUN_MOD
{
MOD_RT,MOD_NRT,};
Ctx(RUN_MOD runType)
{
if(runType == MOD_RT)
{
Ctx();
}
}
Ctx()
{
m_L = malloc(100);
std::cout << "set m_L=" << m_L << std::endl;
}
void print()
{
std::cout <<"print() m_L=" << m_L << std::endl;
}
private:
void *m_L;
const char* const ARG_TYPE_NOT_MATCH = "the type of argument is not match";
const char* const ARG_NUM_INVALID = "the number of arguments is invalid";
const char* const STACK_OPS_INPUT_ARG_INVALID = "the input argument passed to the stack ops is invalid";
};
int main()
{
Ctx ctx(Ctx::RUN_MOD::MOD_RT);
ctx.print();
}
set m_L=0x614c20
print() m_L=0x400ad0
你看地址不一样。我确实通过调用 m_L
(由 Ctx::Ctx()
调用)设置了 Ctx::Ctx(RUN_MOD runType)
。我真的很困惑。
解决方法
如果你正在寻找一个干净的解决方案,你可以使用一个函数,默认构造函数应该做什么。这样你就不需要构造函数委托,它不能被有条件地应用,你也不必弄乱放置 new。
最小示例:
class Ctx
{
private:
void DefaultInit()
{
m_L = malloc(100);
std::cout << "set m_L=" << m_L << std::endl;
}
public:
Ctx(RUN_MOD runType)
{
if(runType == MOD_RT)
{
this->DefaultInit();
}
}
Ctx()
{
this->DefaultInit();
}
}
,
构造函数委托只能在构造函数的 member initialization list 内部使用,不能在构造函数体内使用。 This answer 展示了如何完全避免使用构造函数委托,方法是创建一个通用的初始化函数,然后多个构造函数可以根据需要调用该函数。
但是,如果您确实想使用构造函数委托,无论出于何种原因,那么在这种情况下,Ctx()
构造函数应委托给 Ctx(RUN_MOD)
构造函数,而不是您最初尝试的相反方式,例如:
class Ctx
{
public:
enum RUN_MOD
{
MOD_RT,MOD_NRT,};
Ctx(RUN_MOD runType)
{
if (runType == MOD_RT)
{
m_L = malloc(100);
std::cout << "set m_L=" << m_L << std::endl;
}
}
Ctx() : Ctx(MOD_RT) // <— here
{
}
void print()
{
std::cout << "print() m_L=" << m_L << std::endl;
}
private:
void *m_L = nullptr;
const char* const ARG_TYPE_NOT_MATCH = "the type of argument is not match";
const char* const ARG_NUM_INVALID = "the number of arguments is invalid";
const char* const STACK_OPS_INPUT_ARG_INVALID = "the input argument passed to the stack ops is invalid";
};
,
调用任何类的 ctor 都会生成它的一个实例,在您发布的代码中,很明显 Ctx() 中分配的 m_l 不属于由构造的对象Ctx(RUN_MOD runType)
试试下面的代码
void init_m_l()
{
m_L = malloc(100);
std::cout << "set m_L=" << m_L << std::endl;
}
Ctx(RUN_MOD runType)
{
if(runType == MOD_RT)
init_m_l();
}
Ctx()
{
init_m_l();
}
,
我找到了一个解决方案,这是代码片段(https://coliru.stacked-crooked.com/a/964309f60f62dbd4,它有效,但我仍在努力理解它):
#include<iostream>
class Ctx
{
public:
enum RUN_MOD
{
MOD_RT,};
Ctx(RUN_MOD runType)
{
if(runType == MOD_RT)
{
new (this)Ctx();
}
}
Ctx()
{
m_L = malloc(100);
std::cout << "set m_L=" << m_L << std::endl;
}
void print()
{
std::cout <<"print() m_L=" << m_L << std::endl;
}
~Ctx()
{
free(m_L);
}
Ctx(const Ctx&) = delete; //to avoid double free
private:
void *m_L;
const char* const ARG_TYPE_NOT_MATCH = "the type of argument is not match";
const char* const ARG_NUM_INVALID = "the number of arguments is invalid";
const char* const STACK_OPS_INPUT_ARG_INVALID = "the input argument passed to the stack ops is invalid";
};
int main()
{
Ctx ctx(Ctx::RUN_MOD::MOD_RT);
ctx.print();
}
,
这是一个很好的答案,但作者删除了它。 我把它贴在这里供更多人学习。
他的代码:
if(runType == MOD_RT)
{
Ctx();
}
创建一个临时的 Ctx()
对象,然后——就是这样。不多也不少。一旦该行代码执行完毕,该临时文件就会被销毁。
该类还有其他主要问题,例如使用 malloc,该类由于不遵循 3 规则而导致内存泄漏,未初始化所有成员(我通过将 m_L
设置为 {{1 }}) 等
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。