是否可以使用其构造函数重新初始化类的对象?
答案 0 :(得分:70)
排序。鉴于A类:
A a;
...
a = A();
最后一个语句不是初始化,而是赋值,但它可能会做你想要的。
答案 1 :(得分:44)
字面上?是的,通过使用新的展示位置。但首先你必须破坏以前构造的对象。
SomeClass object(1, 2, 3);
...
object.~SomeClass(); // destruct
new(&object) SomeClass(4, 5, 6); // reconstruct
...
// Final destruction will be done implicitly
这个价值并没有超出纯粹的理论范围。不要在实践中这样做。整个事情都难以描述。
答案 2 :(得分:28)
这是可能的,虽然这是一个非常糟糕的主意。原因是如果不调用现有对象上的析构函数,就会泄漏资源。
有了这个重要的警告,如果你坚持这样做,你可以使用新的位置。
// Construct the class
CLASS cl(args);
// And reconstruct it...
new (&cl) CLASS(args);
答案 3 :(得分:11)
答案 4 :(得分:10)
简短回答:
没有。如果要对对象的预期行为的一部分进行多次初始化,那么实现它的最佳方法是通过可访问的初始化方法。您的类的构造函数可以简单地遵循此方法。
class C1 {
public:
C1(int p1, int p2) {
Init(p1,p2);
}
void Init(int p1, int p2) { ... }
};
Nitpicker角落:
在创建对象后,是否有一些令人难以置信的邪恶方式在C ++中调用构造函数?几乎可以肯定,这毕竟是C ++。但它基本上是邪恶的,它的行为几乎肯定不是由标准定义的,应该避免。
答案 5 :(得分:9)
在C ++ 11中,您可以这样做:
#include <type_traits>
template <class T, typename... Args>
void Reconstruct(T& x, Args&&... args)
{
static_assert(!std::has_virtual_destructor<T>::value, "Unsafe");
x.~T();
new (&x) T(std::forward<Args>(args)...);
}
这允许您使用Reconstruct
将任意构造函数参数传递给任何对象。这可以避免必须维护一堆Clear
方法,并且如果在某个时刻对象发生更改,并且Clear
方法不再与构造函数匹配,则很容易忽略这些错误。
以上在大多数情况下都可以正常工作,但如果引用是在具有虚拟析构函数的派生对象中的基础,则会失败。因此,上述实现可防止使用具有虚拟析构函数的对象。
答案 6 :(得分:7)
是的,你可以作弊并使用新的位置。
注意:我不建议这样做:
#include <new>
reInitAnA(A& value)
{
value.~A(); // destroy the old one first.
new (&value) A(); // Call the constructor
// uses placement new to construct the new object
// in the old values location.
}
答案 7 :(得分:4)
我通常在现代C ++中编写以下内容:
SomeClass a;
...
a = decltype(a)();
这可能不是最有效的方式,因为它有效地构建了同一类型a
的另一个对象并将其分配给a
,但它在大多数情况下都有效,你不会这样做。必须记住a
的类型,如果类型发生变化,它会适应。
答案 8 :(得分:2)
可能不是你的想法,但由于你没有提到它的用途,我想一个答案是你通过控制范围和程序流来做到这一点。
例如,你不会写这样的游戏:
initialize player
code for level 1
...
reinitialize player
code for level 2
...
etc
相反,你会努力:
void play_level(level_number, level_data) {
Player player; //gets "re-initialized" at the beginning of each level using constructor
//code for level
}
void game() {
level_number = 1;
while (some_condition) {
play_level(level_number, level_data);
++level_number;
}
}
(传达这个想法的粗略轮廓,并不意味着可远程编辑。)
答案 9 :(得分:2)
不像上面的一些答案所暗示的那样破坏和重新初始化,最好像下面那样进行分配。下面的代码是异常安全的。
T& reinitialize(int x, int y)
{
T other(x, y);
Swap(other); // this can't throw.
return *this;
}
答案 10 :(得分:0)
尽管大多数答案都需要两个步骤来重新初始化对象;首先,创建一个初始对象,然后创建另一个对象,并使用placement new
将其与第一个对象交换,此答案涉及以下情况:首先创建一个指向空对象的指针,然后分配并构造它:>
class c *c_instance; // Pointer to class c
c_instance = new c(arg1, ..., argn) // Allocate memory & call the proper constructor
// Use the instance e.g. c->data
delete c_instance; // Deallocate memory & call the destructor
答案 11 :(得分:0)
是的,有可能。 如果您创建一个返回新对象的方法。
#include "iostream"
class a // initialize class
a getNewA(a object){// Create function to return new a object
a new_object(/*Enter parameters for constructor method*/);
return new_object;
}
答案 12 :(得分:0)
如果你真的必须这样做,我强烈建议你为此创建一个重置方法:
class A
{
...
public:
reset() { *this= A() };
}
以上要求 A 是可复制和移动的。 那是因为最初的优化版本将从临时文件中复制。但是复制省略可能会删除这一步。
A::reset() 的行为总是明确定义的。它将有效 A 实例中的现有数据替换为来自新实例的数据。当然,如果您还希望重新初始化 A 的数据,则 A 的任何子类仍需要定义自己的版本。但是,不这样做本身并不会引起未定义或未指定的行为。它只是意味着只有 A 为其成员使用的内存才会被重置。甚至虚拟函数和/或虚拟继承的参与也不会改变这一点。虽然使用这些东西的通常警告适用。
原始指针不会被上述删除,因此需要将它们放入 std::shared_ptr 或类似结构中,以便在不再需要时自毁。