我在c ++中有一个函数,它有一个我构建的对象的2个可选c'tor(一个带有向量“vals”和其他没有的东西)。
...
RecievedMessage a(sc, type);
if (!vals.empty()){
//a.~RecievedMessage();
RecievedMessage a(sc, type, vals);
}
return &a;
}
//中的行是可选的。
是否有效(有或没有可选线)?为什么?如果不是,如何在没有“vals”的setter的情况下修复它? 非常感谢。
答案 0 :(得分:3)
不,它不起作用。
RecievedMessage a(sc, type);
// Here we construct 'a'
if (!vals.empty()){
//a.~RecievedMessage();
// If we enable this line, we destroy 'a'
RecievedMessage a(sc, type, vals);
// Here we construct a second 'a' that only exists in this block
}
// End of block: The inner 'a' is destroyed here automatically
return &a;
}
// End of block: The outer 'a' is destroyed here, again.
两次销毁对象具有未定义的行为。你不希望这样。
如果你不手动调用析构函数,外部a
只会被销毁一次,这很好。
但在任何一种情况下,RecievedMessage a(sc, type, vals);
都与外部a
无关,只会创建另一个变量。
有很多方法可以解决这个问题,但是代码的最后几行使它毫无意义:
return &a;
您将返回本地变量的地址。这本身就是破坏的:当函数返回时,它的所有局部变量都会被自动销毁,所以你返回的是一个无效的指针。
答案 1 :(得分:2)
你的代码到处都是,但我认为你正在寻找的是这样的:
ReceivedMessage *MakeReceivedMessage (foo sc, bar type, vector<whatever>& vals)
{
if (vals.empty())
return new ReceivedMessage (sc, type);
return new ReceivedMessage (sc, type, vals);
}
当然,在这个例子中最好只有一个构造函数并让对象测试vals
在适当的时候是否为空,但是,一般来说,你可以随时调用你喜欢的任何构造函数。只需正确管理对象的生命周期(并且不要 - 永远 - 返回指向堆栈中对象的指针)。
示例用法(用于管理正确返回的对象的生命周期):
std::unique_ptr<ReceivedMessage> MyReceivedMessage (MakeReceivedMessage (...));
MyReceivedMessage->DoFunkyStuffWithMessage ();
....
或者,正如melpomene指出的那样,您可以首先返回std::unique_ptr<ReceivedMessage>
。有些人(很多?)会更喜欢这样。您可以使用std::make_unique构建它。
答案 2 :(得分:1)
目前您的代码存在三个主要问题:
首先,您对析构函数PdfStamper
的注释调用不应该存在。在C ++中,当对象的生命周期结束时(或者当它超出范围时,或者当~ReceivedMessage()
被动态分配delete
时调用new
)时,会自动调用对象的析构函数。虽然在某些情况下显式调用析构函数是必要的(例如“放置新的”),但这些情况是您不太可能遇到的情况。
其次,内部RecievedMessage a(sc, type, vals);
中的if
声明不会替换外部作用域中a
的值。这只会创建另一个同名的变量,该变量会遮蔽外部a
,而外部作用域中的return &a;
只能引用外部a
。此时内部a
已不再存在,因为它已超出范围。
解决此问题的方法是使用a
运算符并构建临时=
来为ReceivedMessage
分配新值:
if (!vals.empty()) {
a = ReceivedMessage(sc, type, vals);
}
只要为operator=
定义(隐式或其他)正确的ReceivedMessage
,这应该有效。
第三,你的函数返回一个指向局部变量a
的指针。由于C ++中的对象一旦超出范围就被销毁,到函数返回时a
不再存在,因此调用代码获得的ReceivedMessage *
指针无效且未定义取消引用该指针并使用它的行为。
此问题有几个问题:
第一个选项不是返回指针(ReceivedMessage *
),而是按值返回ReceivedMessage
。
ReceivedMessage foo()
{
ReceivedMessage a(123);
return a;
}
只要为ReceivedMessage
定义(隐式或其他)正确的副本或移动构造函数,这应该有效。
第二个选项是使用std::unique_ptr
,然后让您的函数返回std::unique_ptr<ReceivedMessage>
。
#include <memory>
std::unique_ptr<ReceivedMessage> foo()
{
std::unique_ptr<ReceivedMessage> a;
if (vals.empty()) {
a = std::make_unique<ReceivedMessage>(sc, type);
} else {
a = std::make_unique<ReceivedMessage>(sc, type, vals);
}
return a;
}
此方法的优点是unique_ptr
可以为空,因此您可以创建空unique_ptr
,而无需立即构建ReceivedMessage
。此外,您可以安全地移动和分配unique_ptr
值,而无需定义正确的operator=
或正确的复制/移动构造函数。
使用unique_ptr
时,调用代码可能如下所示:
std::unique_ptr<ReceivedMessage> message = foo();
foo->bar();
而不是直接使用ReceivedMessage
时的以下内容:
ReceivedMessage message = foo();
foo.bar();