Как сохранить значение локальной переменной и вернуться на улицу в C ++ - PullRequest
1 голос
/ 29 июня 2010

Я использую boost shared_ptr, чтобы обернуть указатель. Однако я могу получить только правильное значение в test_shared_ptr (), а в main () я получаю неправильное значение.

Ожидаемый результат:
100
100

Фактический объем производства:
100
-572662307

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

Ниже приведен исходный код.

#include <memory>
#include <iostream>


class TestClass
{
public:
    TestClass(int &i);
    void print_i();
private:
    int *_i;
};

TestClass::TestClass(int &i) : _i(&i)
{

}

void TestClass::print_i()
{
    std::cout << *_i << std::endl;
}


void print_i(int &i)
{
    std::cout << i << std::endl;
}

TestClass *test_shared_ptr()
{
    std::tr1::shared_ptr<int> i(new int());

    *i = 100;

    print_i(*i); 

    return new TestClass(*i);
}


int main(int argc, char** argv)
{
    TestClass *p = test_shared_ptr();
    p->print_i();
    return 0;
}

Ответы [ 4 ]

6 голосов
/ 29 июня 2010

Вам нужно передавать общий указатель, а не ссылки и указатели непосредственно в int.

Что происходит, так это то, что общий указатель никогда не передается нигде, кроме функции test_shared_ptr ().Когда эта функция возвращается, общий указатель уничтожается.Когда он видит, что ничто другое не имеет ссылки на его память, он уничтожает память, на которую он указывал.

В основном, когда вы используете int &i и int *i, измените оба значения на std::tr1::shared_ptr<int> i.

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

2 голосов
/ 29 июня 2010

Кажется, что указатель становится недействительным в этом случае

Конечно, он становится недействительным. shared_ptr удаляется, когда вы покидаете test_shared_ptr, и после этого я не существует.

Есть ли правильный подход к выполнению работы?

1) просто скопируйте значение i. (используйте int i вместо int * i в TestClass). int маленький, вы ничего не потеряете.

или

2) использовать std :: tr1 :: shared_ptr вместо int * в TestClass.

1 голос
/ 29 июня 2010

Проблема связана с контрактом API.

Я не хочу использовать разделяемый указатель для передачи значений переменных в конструкторе TestClass, поскольку я не хочу заставлять пользователя API использовать умный указатель

Ваш TestClass контракт в настоящее время выглядит так, как будто вы хотите, чтобы вызывающая сторона сохранила элемент int, чтобы срок его службы превышал TestClass.

Однако ваш тестовый пример не соответствует этому правилу договора.

На самом деле я хочу передать объект по ссылке вместо общего типа в моем приложении.

Передача по ссылке или по указателю не имеет ничего общего с типом «универсальный».

Вот возможное исправление для вашего кода, тестирующего ваш API, тогда область действия вашего int будет длиннее, чем достаточно длинная (до конца приложения), чтобы обрабатывать все случаи использования в TestClass

TestClass *test_shared_ptr(int &i)
{
    i = 100;

    print_i(i); 

    return new TestClass(i);
}


int main(int argc, char** argv)
{
    std::tr1::shared_ptr<int> i(new int());

    TestClass *p = test_shared_ptr(*i);
    p->print_i();
    return 0;
}
0 голосов
/ 29 июня 2010

То, что вы делаете, действительно разрушает точку shared_ptr. В основном, когда вы отдаете его из этой функции, он должен волшебным образом сломаться и, таким образом, не освободить остроконечную память?

Нет. Это освобождает это. Ожидаете ли вы, что shared_ptr все еще существует вне функции, поэтому, когда «p» выходит из области видимости, ему удается вызвать деструктор shared_ptr? Этого не может быть p - указатель, а не класс shared_ptr.

Либо верните shared_ptr, либо верните указатель new'd и удалите его самостоятельно.

...