How to return a reference to a variable in C++?
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& t开发者_StackOverflowitle, 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?
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 if something()
did happen to return a reference to an already-existing thing. This is because the type of bar
is Foo
, and not Foo&
. bar
must hold its own Foo
; it cannot refer to one, because it isn't a reference. And since the Foo
returned by something()
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. :/
Your variable msgBox
in the function createMessageBox
is scoped to the function i.e. when you return from createMessageBox
, 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:
QMessageBox* msgBox = new QMessageBox;
msgBox->setWindowTitle(title);
msgBox->setText(message);
msgBox->setStandardButtons(buttons);
Then, you need to return a pointer to the variable:
QMessageBox* MessageBoxes::createMessageBox(const QString& message, const QString&, QMessageBox::StandardButtons buttons) {
...
return msgBox;
}
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 :)
If you want to return a messageBox from createMessageBox, you should allocate it from the heap
QMessageBox *MessageBoxes::createMessageBox(const QString& message, const QString& title, QMessageBox::StandardButtons buttons) {
QMessageBox *pMsgBox = new QMessageBox();
pMsgBox->setWindowTitle(title);
pMsgBox->setText(message);
pMsgBox->setStandardButtons(buttons);
return pMsgBox;
}
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.
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:
QMessageBox * MessageBoxes::createMessageBox(const QString& message, const QString& title, QMessageBox::StandardButtons buttons) {
QMessageBox *pMsgBox = new QMessageBox();
pMsgBox->setWindowTitle(title);
pMsgBox->setText(message);
pMsgBox->setStandardButtons(buttons);
return pMsgBox;
}
Calling code:
QMessageBox *qMBox = createMessageBox(X, Y, Z);
//working with qMBox
delete qMBox; //must deallocate the memory when you don't need it anymore!
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.
Transferring ownership is done via std::unique_ptr<T>
in C++0x:
#include <memory>
std::unique_ptr<QMessageBox> MessageBoxes::createMessageBox
(const QString& message, const QString& title, QMessageBox::StandardButtons buttons)
{
std::unique_ptr<QMessageBox> msgBox(new QMessageBox);
msgBox->setWindowTitle(title);
msgBox->setText(message);
msgBox->setStandardButtons(buttons);
return msgBox;
}
auto m = createMessageBox(message, title, buttons);
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.
精彩评论