在c++中定义对象而不调用其构造函数
Defining an object without calling its constructor in C++
在c++中,我希望像这样将对象定义为类的成员:
Object myObject;
然而,这样做将尝试调用它的无参数构造函数,该构造函数不存在。但是,我需要在包含类完成一些初始化之后调用构造函数。像这样。
class Program
{
public:
Object myObject; //Should not try to call the constructor or do any initializing
Program()
{
...
//Now call the constructor
myObject = Object(...);
}
}
存储指向Object
而不是实际Object
的指针
:
class Program
{
public:
Object* myObject; // Will not try to call the constructor or do any initializing
Program()
{
//Do initialization
myObject = new Object(...); // Initialised now
}
}
别忘了在析构函数中delete
它。现代c++在这方面提供了帮助,您可以使用auto_ptr shared_ptr而不是原始内存指针。
其他人已经发布了使用原始指针的解决方案,但智能指针将是一个更好的主意:
class MyClass {
std::unique_ptr<Object> pObj;
// use boost::scoped_ptr for older compilers; std::unique_ptr is a C++0x feature
public:
MyClass() {
// ...
pObj.reset(new Object(...));
pObj->foo();
}
// Don't need a destructor
};
这避免了添加析构函数的需要,并且隐式地禁止复制(除非您自己编写operator=
和MyClass(const MyClass &)
)。
如果您想避免单独的堆分配,可以使用boost的aligned_storage
和placement new来完成。测试:
template<typename T>
class DelayedAlloc : boost::noncopyable {
boost::aligned_storage<sizeof(T)> storage;
bool valid;
public:
T &get() { assert(valid); return *(T *)storage.address(); }
const T &get() const { assert(valid); return *(const T *)storage.address(); }
DelayedAlloc() { valid = false; }
// Note: Variadic templates require C++0x support
template<typename Args...>
void construct(Args&&... args)
{
assert(!valid);
new(storage.address()) T(std::forward<Args>(args)...);
valid = true;
}
void destruct() {
assert(valid);
valid = false;
get().~T();
}
~DelayedAlloc() { if (valid) destruct(); }
};
class MyClass {
DelayedAlloc<Object> obj;
public:
MyClass() {
// ...
obj.construct(...);
obj.get().foo();
}
}
或者,如果Object
是可复制的(或可移动的),您可以使用boost::optional
:
class MyClass {
boost::optional<Object> obj;
public:
MyClass() {
// ...
obj = Object(...);
obj->foo();
}
};
您可以通过这个技巧完全控制对象的构造和销毁:
template<typename T>
struct DefferedObject
{
DefferedObject(){}
~DefferedObject(){ value.~T(); }
template<typename...TArgs>
void Construct(TArgs&&...args)
{
new (&value) T(std::forward<TArgs>(args)...);
}
public:
union
{
T value;
};
};
应用于您的样品:
class Program
{
public:
DefferedObject<Object> myObject; //Should not try to call the constructor or do any initializing
Program()
{
...
//Now call the constructor
myObject.Construct(....);
}
}
这个解决方案的最大优点是,它不需要任何额外的分配,并且对象内存分配正常,但是您可以控制何时调用构造函数。
另一个示例链接
如果您可以访问boost,则提供了一个方便的对象,称为boost::optional<>
-这避免了动态分配的需要,例如
class foo
{
foo() // default std::string ctor is not called..
{
bar = boost::in_place<std::string>("foo"); // using in place construction (avoid temporary)
}
private:
boost::optional<std::string> bar;
};
如果您可以将其他初始化移到构造函数中,您也可以重写代码以使用构造函数初始化列表:
class MyClass
{
MyObject myObject; // MyObject doesn't have a default constructor
public:
MyClass()
: /* Make sure that any other initialization needed goes before myObject in other initializers*/
, myObject(/*non-default parameters go here*/)
{
...
}
};
您需要意识到,遵循这样的模式将导致您在构造函数中进行大量工作,这反过来又导致需要掌握异常处理和安全性(因为从构造函数返回错误的规范方法是抛出异常)。
您可以使用指针(或智能指针)来完成此操作。如果不使用智能指针,请确保代码在删除对象时释放内存。如果你用的是智能笔,就不用担心了。
class Program
{
public:
Object * myObject;
Program():
myObject(new Object())
{
}
~Program()
{
delete myObject;
}
// WARNING: Create copy constructor and = operator to obey rule of three.
}
涉及匿名联合和放置new
的技巧这与jenkas的回答相似,但更直接
class Program
{
public:
union{
Object myObject;
}; //being a union member in this case prevents the compiler from attempting to call the (undefined) default constructor
Program()
{
...
//Now call the constructor
new (&myObject) Object(...);
}
~Program()
{
myobject.~Object(); //also make sure you explicitly call the object's destructor
}
}
然而,问题是现在必须显式定义所有特殊的成员函数,因为编译器默认会删除它们。
您可以使用union
联合的成员未初始化
尝试创建union
template <typename T>
union uninitialized_value_of
{ T value; };
当你想要获得一个未初始化的值时。创建一个类型为uninitialized_value_of
的对象,并引用其成员value
class Program
{
uninitialized_value_of<Object> MyObject;
//Rest of your class
//...
}
<代码>代码>
class Program
{
uninitialized_value_of<Object> MyObject;
//Rest of your class
//...
}
- 在c++中使用向量时,如何调用构造函数和析构函数
- C++:考虑但不调用构造函数的特殊性
- 对象实例化调用构造函数的次数太多
- 我使用向量来创建类对象列表.初始化向量时如何使用参数调用构造函数?
- C ++:通过大括号调用构造函数?
- 不能调用构造函数
- 赋值 boost::intrusive_ptr 而不调用构造函数?
- 在模板化类的构造函数中调用构造函数
- 如何为 std::vector 分配内存,然后稍后为某些元素调用构造函数?
- 为什么从另一个构造函数内部调用C++构造函数不修改类变量?
- 静态 std::map instatiation 在类的方法中调用构造函数吗?
- 有没有一种简单的方法可以在对象向量上调用构造函数?
- 我不明白在这个例子中什么时候调用构造函数
- 调用c++构造函数的不同方法
- 调用构造函数与将内联常量定义为默认参数
- 如何通过 Rust FFI 调用C++构造函数?
- "new"运算符是否总是调用构造函数?
- 无法调用构造函数
- 使用 "()" 调用构造函数不同于"{}"
- 确定是调用构造函数还是强制转换运算符的因素