如何返回对 C++ 中变量的引用?

发布于 2024-11-29 11:16:30 字数 1662 浏览 1 评论 0原文

我有一个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

╭⌒浅淡时光〆 2024-12-06 11:16:30

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 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. :/

逆流 2024-12-06 11:16:30

函数 createMessageBox 中的变量 msgBox 的作用域为该函数,即当您从 createMessageBox 返回时,msgBox 被销毁(从堆栈中取出),因此您无法引用它。如果语义是让调用者获得变量的所有权,则返回引用并不是传达它的最佳方式。

首先,您需要动态分配 msgBox

QMessageBox* msgBox = new QMessageBox;
msgBox->setWindowTitle(title);
msgBox->setText(message);
msgBox->setStandardButtons(buttons);

然后,您需要返回一个指向该变量的指针:

QMessageBox* MessageBoxes::createMessageBox(const QString& message, const QString&, QMessageBox::StandardButtons buttons) {
    ...
    return msgBox;
}

即使这并不能真正告诉调用者他们正在获取该变量的所有权。由于它只是一个私有方法,这可能不太重要,但您应该记录调用者何时应该取得所有权。更好的是,您可以使用智能指针来消除对此类文档的需要:)

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 :)

緦唸λ蓇 2024-12-06 11:16:30

如果你想从createMessageBox返回一个messageBox,你应该从堆中分配它。

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;
}

这将返回一个指向messageBox的指针。如果删除指针失败,就会泄漏内存。

当函数返回时,您想要返回引用的本地将不再存在。即使您获取了它的地址 &msgBox 并将其返回,当您尝试使用它时也会破坏堆栈。在函数返回后,MessageBox 继续存在的唯一方法是使用 new 创建它。

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.

月下客 2024-12-06 11:16:30

您不能返回局部变量的引用,因为函数返回后局部变量不存在,但调用代码可能仍然使用对不再存在的对象的引用。

由于 QMessageBox 的复制构造函数已禁用,因此您也无法按值返回它。

您必须将其返回一个指向动态创建的对象的指针,如下所示:

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;
}

调用代码:

QMessageBox *qMBox = createMessageBox(X, Y, Z);
//working with qMBox

delete qMBox; //must deallocate the memory when you don't need it anymore!

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!
千鲤 2024-12-06 11:16:30

我想在不同的函数中检索由此方法创建的对象,以便这个新函数获得该对象的所有权。

在 C++0x 中,所有权的转移是通过 std::unique_ptr 完成的:

#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);

请注意,不需要手动删除,智能指针已经处理好了这一点。

在 C++03 中,您可以使用即将弃用的 std::auto_ptr 来代替。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文