MCVE
#include <map>
class A{
public:
A(int){
}
};
class B : public A{
public:
B()
: A(filter()){}
int filter(){
std::map<int,int> aStuff;
//new(&m_aStuff)std::map<int,int>;
m_aStuff = aStuff;
return 0;
}
private:
std::map<int,int> m_aStuff;
};
int main(){
B b;
return 0;
}
这在编译时失败,因为m_aStuff未初始化。 使用answer我添加了
new(&m_aStuff)std::map<int,int>;
如果取消注释该行在编译时运行,但是当你离开过滤器类时,无论如何都会重新初始化m_aStuff。
答案 0 :(得分:1)
我强烈建议您重新考虑设计,但这是我的解决方案:
class A {
public:
A(int) {}
};
class B : public A {
public:
struct Dirty {
std::map<int, int> map;
};
B(Dirty dirt = Dirty()) : A(filter(dirt)), m_aStuff(std::move(dirt.map)) {}
int filter(Dirty& dirt) {
std::map<int, int> aStuff;
//new(&m_aStuff)std::map<int,int>;
dirt.map = aStuff;
return 0;
}
private:
std::map<int, int> m_aStuff;
};
int main() {
B b;
return 0;
}
更好的解决方案:
class B : public A {
public:
B() : B(filter()) {}
private:
B(std::tuple<int, std::map<int, int>> t)
: A(std::get<0>(t)), m_aStuff(std::move(std::get<1>(t))) {}
static std::tuple<int, std::map<int, int>> filter() {
std::map<int, int> aStuff;
//new(&m_aStuff)std::map<int,int>;
return make_tuple(0, aStuff);
}
std::map<int, int> m_aStuff;
};
答案 1 :(得分:1)
作为你未提出的问题“如何修复它?” Yuki在没有任何细节的情况下回答我会提供一个答案“那里发生了什么?”。
在C ++中,对象是从基类构造的。所以订单如下:
A::A(int); // base class constructor
B::B(); // inherited class constructor
所有成员对象都在初始化列表中初始化:
B::B()
: // Initializer list begin.
A(), // Base class initialized first.
m_aStuff() // Members of current class are initialized next.
{ // End of initializer list.
// All members are safe to use.
}
这是对象初始化的顺序。正如您在此处所见,成员m_aStuff
在基础构造函数A::A(int)
之后初始化。
构造函数是一个成员函数,因为每个函数都需要求值参数。因此在初始化对象之前调用函数int B::filter()
。这意味着成员变量也未初始化。换句话说,执行顺序是:
B::filter()
B::m_aStuff
A::A(int)
B::m_aStuff
显然,第2步是在初始化之前修改变量。根据{{1}}的实现,这可能会导致不同的行为(可能是未定义的)。
事实上,以下两个结构是相同的:
std::map
和
B::B() :
A(0)
{}
但在第二种情况下,您是显式初始化它,而在第一种情况下,编译器将为您生成此代码。
您的解决方案B::B() :
A(0),
m_aStuff()
{}
在使用之前初始化对象,这会使行为更加明确。但接下来生成的类new(&m_aStuff)std::map<int,int>;
的构造函数将启动,B
将再次初始化。这会将你的地图设置为初始状态(虽然我可以想象内存会泄漏的场景)。