Как вернуть ссылку на переменную в C ++? - PullRequest
0 голосов
/ 12 августа 2011

У меня есть статический класс 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 и предположил, что он вернет ссылку, но, похоже, не работает таким образом.Есть идеи, как мне это сделать?

Ответы [ 5 ]

3 голосов
/ 12 августа 2011

0) Мы не делаем этого "статического класса" в C ++.Это хитрости, связанные с тем фактом, что Java и C # заставляют вас помещать весь ваш код в классы.C ++ этого не делает, поэтому мы не должны обходить ограничения, которых не существует.Классы не являются местом хранения кода;они существуют для определения типа данных .Что вы действительно пытаетесь сделать, так это организовать код, сгруппировав его под общим именем;мы делаем это с namespace.

1) Вы не можете возвращать ссылку на локальную переменную.Ссылки предназначены для возврата уже существующих вещей.

2) Вы не хотите возвращать ссылку, потому что цель createMessageBox - создать aокно сообщения.Вы возвращаете значение: окно сообщения, которое было создано.

3) Когда вы пишете

Foo bar = нечто ();

результат из something() равен скопировано , , даже если something() действительно вернул ссылку на уже существующую вещь.Это потому, что тип bar равен Foo, а не Foo&.bar должен иметь свой собственный Foo;это не может относиться к одному, потому что это не ссылка.И так как Foo, возвращаемое something(), является самостоятельным значением, с его собственным расположением в памяти, мы не можем просто заставить его быть "быть" bar;программа должна сделать копию.

Чтобы обратиться к результату функции, вы должны написать Foo& bar = something();.Это продлит срок жизни возвращаемого объекта (который обычно сразу выходит из области видимости), поэтому нет проблем с обращением к временному.

4) Однако оптимизирующие компиляторы умны,и это вряд ли вам что-нибудь даст .Если вы просто возвращаете значение и присваиваете по значению, шансы хороши, что копирование на самом деле не произойдет (хотя стандарт говорит, что ваш код должен быть подготовлен к такой возможности).

5) Динамическое распределениечестно, очень плохая идея здесь.Если вы должны сделать это, по крайней мере, используйте какую-нибудь оболочку смарт-указателя.Хотя, когда ваш конструктор копирования отключен, иногда вы застреваете с такими вещами.: /

0 голосов
/ 12 августа 2011

Я хотел бы получить объект, созданный этим методом, в другой функции, чтобы эта новая функция стала владельцем объекта.

Передача права собственности осуществляется через std::unique_ptr<T> в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);

Обратите внимание, что руководство delete не требуется, умный указатель уже позаботится об этом.

В C ++ 03 вы можете использовать-это не рекомендуется std::auto_ptr<T>.

0 голосов
/ 12 августа 2011

Ваша переменная msgBox в функции createMessageBox ограничена функцией, т. Е. Когда вы возвращаетесь из 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;
}

Даже это на самом деле не говорит вызывающей стороне, что они принимают владение переменной.Поскольку это только частный метод, это может не иметь большого значения, но вы должны задокументировать, когда вызывающий объект должен стать владельцем.Более того, вы могли бы использовать умные указатели, чтобы устранить необходимость в такой документации:)

0 голосов
/ 12 августа 2011

Если вы хотите вернуть messageBox из createMessageBox, вы должны выделить его из кучи

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

Возвращает указатель на блок сообщений. Если вам не удастся удалить указатель, это приведет к утечке памяти.

Локальный объект, на который вы хотите вернуть ссылку, перестает существовать, когда возвращается ваша функция. Даже если вы взяли адрес it & msgBox и вернули его, вы уничтожите стек, когда попытаетесь его использовать. Единственный способ, чтобы MessageBox продолжал существовать после возврата вашей функции, это создать ее с помощью new.

0 голосов
/ 12 августа 2011

Вы не можете вернуть ссылку локальной переменной, потому что локальная переменная не существует после возврата функции, но вызывающий код все еще может использовать ссылку на объект, который больше не существует. 1003 *

И так как конструктор копирования отключен для 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!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...