我想在下面的代码中将MyClass保存在堆栈内存中(更简单,更快),但是避免调用默认构造函数:
#include <iostream>
class MyClass {
public:
MyClass() {
std::cout << "MyClass()" << std::endl;
}
MyClass(int a) {
std::cout << "MyClass(" << a << ")" << std::endl;
}
MyClass(const std::string& a) {
std::cout << "MyClass(\"" << a << "\")" << std::endl;
}
void doStuff() {
std::cout << "doStuff()" << std::endl;
}
};
int main(int argc, char* argv[]) {
bool something;
if (argc > 1)
something = 1;
else
something = 0;
MyClass c;
if (something)
c = MyClass(1);
else
c = MyClass("string");
c.doStuff();
return 0;
}
据我所知,避免调用默认构造函数的唯一方法是使用指针,但是我必须在堆中分配并处理内存管理。还有其他办法吗?
答案 0 :(得分:13)
如果您不介意使用完全黑客攻击,则可以尝试展示位置new
。
char mem[sizeof(MyClass)] alignas(MyClass);
auto custom_deleter = [](MyClass *p){ p->~MyClass(); };
std::shared_ptr<MyClass> c(new (mem) MyClass, custom_deleter);
使用alignas
确保为您的对象正确对齐分配的自动内存。 custom_deleter
函数调用析构函数而不释放内存,这在使用具有智能指针的自动内存时是必需的。可以找到代码演示here。
但是,对于您的问题,存在更优雅的解决方案。您可以改为使用复制构造函数:
MyClass c = something ? MyClass(1) : MyClass("string");
c.doStuff();
答案 1 :(得分:5)
if (something) {
MyClass c(1);
c.doStuff();
}
else {
MyClass c("string");
c.doStuff();
}
我建议你创建堆的对象,但是将内存处理委托给另一个类。使用C ++ 03,可以使用std::auto_ptr类。使用C ++ 11时,不推荐使用auto_ptr,而是可以使用shared_ptr或unique_ptr。
以下是使用shared_ptr -
的一些示例代码std::shared_ptr<MyClass> c;
if (something)
c.reset(new MyClass(1));
else
c.reset(new MyClass("string"));
c->doStuff();
当对象超出范围时,将自动删除该对象。
通常,建议使用智能指针而不是自己进行内存管理。当您处理可能抛出异常的代码时,这尤其有用。
答案 2 :(得分:5)
Benjamin Bannier的建议适用于GCC 4.7.2,没有特殊的编译器标志(即默认优化),或者-O0
,-O1
,-O2
或{{1 }}:
-O3
当我在GCC 3.4.4(大约2004年),GCC 3.4.6(2006年),GCC 4.2.4(2007年)和GCC 4.7.2(2012年)上尝试时,我得到了相同的结果。
答案 3 :(得分:2)
尝试,由于编译器复制省略,这可能会避免额外的复制:
MyClass makeInstance(int a, string& b) {
if (something) {
return MyClass(a);
} else {
return MyClass(b);
}
}
我试过了,在我的情况下,我看到只有一个对象被构建和销毁。
答案 4 :(得分:0)
只有一个很好的解决方案可以避免任何不必要的构造函数调用:延迟初始化。只有一个构造函数,它只是让您的对象进入已定义的状态,并在init()
方法中进行实际初始化。像这样:
class MyClass {
public:
MyClass() : initialized(false) { std::cout << "MyClass()" << std::endl; };
void init(int a) {
std::cout << "MyClass(" << a << ")" << std::endl;
initialized = true;
};
void init(const std::string& a) {
std::cout << "MyClass(\"" << a << "\")" << std::endl;
initialized = true;
};
void doStuff() {
assert(initialized);
std::cout << "doStuff()" << std::endl;
};
private:
bool initialized;
};
然后你可以轻松地执行以下操作,在不使用任何类型的黑客攻击的情况下初始化对象一次:
MyClass c;
if (something) {
c.init(1);
} else {
c.init("string");
}
c.doStuff();