如何返回对 C++ 中变量的引用?
我有一个 C++ 静态类,其中包含创建对象的方法。我想在不同的函数中检索此方法创建的对象,以便这个新函数获得该对象的所有权。这是我到目前为止的代码:
MessageBoxes.h
class MessageBoxes {
public:
static int info(const QString& message, const QString& title = _("Information"), QMessageBox::StandardButtons buttons = QMessageBox::Ok);
static int confirmation(const QString& message, const QString& title = _("Confirmation"), QMessageBox::StandardButtons buttons = QMessageBox::Ok | QMessageBox::Cancel);
static int error(const QString& message, const QString& title = _("Error"), QMessageBox::StandardButtons buttons = QMessageBox::Ok);
private:
static QMessageBox& createMessageBox(const QString& message, const QString& title = "", QMessageBox::StandardButtons buttons = QMessageBox::Ok);
};
MessageBoxes.cpp
QMessageBox& MessageBoxes::createMessageBox(const QString& message, const QString& title, QMessageBox::StandardButtons buttons) {
QMessageBox msgBox;
msgBox.setWindowTitle(title);
msgBox.setText(message);
msgBox.setStandardButtons(buttons);
return msgBox;
}
int MessageBoxes::confirmation(const QString& message, const QString& title, QMessageBox::StandardButtons buttons) {
QMessageBox m = createMessageBox(message, title, buttons);
return m.exec();
}
问题是在行 QMessageBox m = createMessageBox(message, title, Buttons)
,编译器告诉我 QMessageBox 的复制构造函数被禁用。这很好,但是我不想制作副本,我想获取在 createMessageBox
中创建的实际对象。我将 createMessageBox
的返回类型声明为 QMessageBox&假设它会返回引用,但似乎并非如此。知道我该怎么做吗?
I have a C++ static class with a method that creates an object. I would like to retrieve the object created by this method in a different function so that this new function takes ownership of the object. This is the code I have so far:
MessageBoxes.h
class MessageBoxes {
public:
static int info(const QString& message, const QString& title = _("Information"), QMessageBox::StandardButtons buttons = QMessageBox::Ok);
static int confirmation(const QString& message, const QString& title = _("Confirmation"), QMessageBox::StandardButtons buttons = QMessageBox::Ok | QMessageBox::Cancel);
static int error(const QString& message, const QString& title = _("Error"), QMessageBox::StandardButtons buttons = QMessageBox::Ok);
private:
static QMessageBox& createMessageBox(const QString& message, const QString& title = "", QMessageBox::StandardButtons buttons = QMessageBox::Ok);
};
MessageBoxes.cpp
QMessageBox& MessageBoxes::createMessageBox(const QString& message, const QString& title, QMessageBox::StandardButtons buttons) {
QMessageBox msgBox;
msgBox.setWindowTitle(title);
msgBox.setText(message);
msgBox.setStandardButtons(buttons);
return msgBox;
}
int MessageBoxes::confirmation(const QString& message, const QString& title, QMessageBox::StandardButtons buttons) {
QMessageBox m = createMessageBox(message, title, buttons);
return m.exec();
}
The problem is that at the line QMessageBox m = createMessageBox(message, title, buttons)
, the compiler tells me that the copy constructor of QMessageBox is disabled. This is fine, however I do not want to make a copy, I want to get the actual object that was created in createMessageBox
. I declared the return type of createMessageBox
as QMessageBox& assuming that it would return the reference but it doesn't seem to work that way. Any idea how I can do that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
0) 我们不在 C++ 中做这种“静态类”的事情。这些技巧是为了应对 Java 和 C# 强制您将所有代码放入类中这一事实。 C++ 不这样做,所以我们不应该绕过不存在的限制。类不是代码的存储位置;它们的存在是为了定义数据类型。您真正想做的是通过将代码分组到一个通用名称下来组织代码;我们使用
命名空间
来做到这一点。1) 您不得返回对局部变量的引用。引用用于返回已经存在的东西。
2) 您不想返回引用,因为
createMessageBox
的目的是创建消息框。您返回一个值:创建的消息框。3)当你写
Foo bar = Something();
时
something()
的结果被复制,即使something()
确实返回了对某个对象的引用已经存在的东西。这是因为bar
的类型是Foo
,而不是Foo&
。bar
必须拥有自己的Foo
;它不能引用一个,因为它不是一个引用。由于something()
返回的Foo
本身就是一个值,并且在内存中拥有自己的位置,因此我们不能仅仅让它“成为”<代码>栏;该程序必须复制一份。要引用函数的结果,您可以编写
Foo&酒吧=某事();
。这将延长返回对象的生命周期(通常会立即超出范围),因此引用临时对象没有问题。4) 然而,优化编译器很聪明,这不太可能给你带来任何好处。如果您只是返回一个值并按值分配,则很可能复制实际上不会发生(尽管标准实际上表示您的代码必须为这种可能性做好准备)。
5)老实说,动态分配在这里是一个非常糟糕的主意。如果必须这样做,至少使用某种智能指针包装器。不过,当您的复制构造函数被禁用时,有时您会遇到这种情况。 :/
0) We don't do this "static class" thing in C++. Those are hacks to deal with the fact that Java and C# force you to put all your code into classes. C++ does not do that, so we shouldn't hack around a limitation that doesn't exist. Classes are not storage places for code; they exist to define a data type. What you're really trying to do is organize the code by grouping it under a common name; we do that with a
namespace
.1) You may not return a reference to a local variable. References are for returning already-existing things.
2) You don't want to return a reference, because the purpose of
createMessageBox
is to create a message box. You return a value: the message box that was created.3) When you write
Foo bar = something();
the result from
something()
is copied, even ifsomething()
did happen to return a reference to an already-existing thing. This is because the type ofbar
isFoo
, and notFoo&
.bar
must hold its ownFoo
; it cannot refer to one, because it isn't a reference. And since theFoo
returned bysomething()
is a value in its own right, with its own location in memory, we can't just cause it to "be"bar
; the program must make a copy.To refer to the result from the function, you would write
Foo& bar = something();
. This will extend the lifetime of the returned object (which ordinarily would go out of scope right away), so there is no problem with referring to a temporary.4) However, optimizing compilers are smart, and this is unlikely to gain you anything. If you just return a value and assign by value, chances are good the copy will not actually happen (although the Standard says in effect that your code must be prepared for that possibility).
5) Dynamic allocation is, honestly, a really bad idea here. If you must do it, at least use some kind of smart-pointer wrapper. Although, when your copy constructor is disabled, sometimes you're stuck with this sort of thing. :/
函数
createMessageBox
中的变量msgBox
的作用域为该函数,即当您从createMessageBox
返回时,msgBox
被销毁(从堆栈中取出),因此您无法引用它。如果语义是让调用者获得变量的所有权,则返回引用并不是传达它的最佳方式。首先,您需要动态分配
msgBox
:然后,您需要返回一个指向该变量的指针:
即使这并不能真正告诉调用者他们正在获取该变量的所有权。由于它只是一个私有方法,这可能不太重要,但您应该记录调用者何时应该取得所有权。更好的是,您可以使用智能指针来消除对此类文档的需要:)
Your variable
msgBox
in the functioncreateMessageBox
is scoped to the function i.e. when you return fromcreateMessageBox
,msgBox
is destroyed (taken off the stack) so you cannot have a reference to it. If the semantics are for the caller to take ownership of the variable, returning a reference is not the best way to convey it.Firstly, you need to allocate
msgBox
dynamically:Then, you need to return a pointer to the variable:
Even this does not really tell the caller that they are taking ownership of the variable though. Since it is only a private method this might not matter too much but you should document when the caller is supposed to take ownership. Even better, you could use smart pointers to eliminate the need for such documentation :)
如果你想从createMessageBox返回一个messageBox,你应该从堆中分配它。
这将返回一个指向messageBox的指针。如果删除指针失败,就会泄漏内存。
当函数返回时,您想要返回引用的本地将不再存在。即使您获取了它的地址 &msgBox 并将其返回,当您尝试使用它时也会破坏堆栈。在函数返回后,MessageBox 继续存在的唯一方法是使用 new 创建它。
If you want to return a messageBox from createMessageBox, you should allocate it from the heap
This returns a pointer to the messageBox. If you fail to delete the pointer, it will leak memory.
The local you want to return the reference to, ceases to exist when your function returns. Even if you took the address of it &msgBox and returned that, you would be destroying the stack when you tried to use it. The only way for the MessageBox to continue to exist after your function returns is to create it using new.
您不能返回局部变量的引用,因为函数返回后局部变量不存在,但调用代码可能仍然使用对不再存在的对象的引用。
由于 QMessageBox 的复制构造函数已禁用,因此您也无法按值返回它。
您必须将其返回一个指向动态创建的对象的指针,如下所示:
调用代码:
You cannot return reference of a local variable, because local variable doesn't exist after the function returns, but the calling code might still use the reference to the object which doesn't exist anymore.
And since the copy-constructor is disable for
QMessageBox
, you cannot return it by value also.You've to return it a pointer to a dynamically created object as:
Calling code:
在 C++0x 中,所有权的转移是通过
std::unique_ptr
完成的:请注意,不需要手动
删除
,智能指针已经处理好了这一点。在 C++03 中,您可以使用即将弃用的
std::auto_ptr
来代替。Transferring ownership is done via
std::unique_ptr<T>
in C++0x:Note that no manual
delete
is necessary, the smart pointer already takes care of that.In C++03, you can use the to-be-deprecated
std::auto_ptr<T>
instead.