создать экземпляр для указателя в других областях - PullRequest
0 голосов
/ 07 января 2011

У меня есть два способа создать экземпляр для указателя. Но один из них потерпит неудачу.

class A {
public:
    int num;
};

void testPointer1(A* a){
    a = new A();
    a->num = 10;
}
A* testPointer2(){
    A* a = new A();
    a->num = 10;
    return a;
}
void testPointer() {
    A* a1 = NULL;
    testPointer1(a1); // this one fails
    //cout << a1->num << endl; // segmentation fault

    A* a2 = NULL;
    a2 = testPointer2();
    cout << a2->num << endl;
}

почему testPointer1 не так?

Ответы [ 3 ]

6 голосов
/ 07 января 2011

Синтаксис действителен, но он не выполняет то, что вам нужно, потому что testPointer1() работает с копией указателя, а не с самим указателем. Поэтому, когда вы назначаете адрес вновь выделенному объекту, он присваивается копии, а не исходному указателю a1.

Из-за этого адрес теряется, и вы получаете утечку памяти. Кроме того, поскольку исходный указатель a1 никогда не изменялся, вы попытались разыменовать нулевой указатель, что плохо.

Я бы сказал, testPointer2() - лучший способ сделать это, но если вы хотите, чтобы testPointer1() работал, попробуйте это:

void testPointer1(A*& a)
{
    a = new A();
    a->num = 10;
} 

Тип параметра указывает «ссылку на указатель на A». Таким образом, вместо копии указателя будет передана ссылка на исходный указатель. Ссылка на C ++ - это псевдоним другого объекта. Поэтому, что бы вы ни делали для псевдонима, оно выполняется для исходного объекта.


Дополнительные примечания:

Обратите внимание, что скобки в new A(); действительно значимы, и их наличие или отсутствие имеет значение .

Также обратите внимание, что вы должны вручную delete все new 'отредактировать объекты после того, как закончите с ними, иначе вы получите утечку. Как правило, вы должны обернуть указатель в его собственный класс и реализовать RAII или использовать умный указатель , такой как умные указатели Boost или auto_ptr, для правильного управления памятью и безопасности исключений.

Если вы собираетесь установить значение num при инициализации, почему бы не создать конструктор?

class A
{
public:
    A(int n) : num(n) {}
    int GetNum() const { return num; }
private:
    int num;
};

void testPointer1(A*& a)
{
    a = new A(10);
}  

A* testPointer2()
{
    return new A(10);
}

// auto_ptr example, see link in second note above
std::auto_ptr<A> testPointer3()
{
    return auto_ptr<A>(new A(10));
} 
2 голосов
/ 07 января 2011

Функции testPointer1 работают с копией предоставленного указателя: изменения a в testPointer1 не отражаются для вызывающей стороны.

Это точно так же, как в этомболее простой пример:

void testInt1(int i)
{
    i++;
}

void testInt()
{
    int i = 0;
    testInt1(i);
    // i is still 0
}

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

0 голосов
/ 07 января 2011

Это домашнее задание?

Это кажется очевидным: формальные параметры сохраняются в стеке и восстанавливаются после вызова метода / функции.внутри функции / метода не изменит свое значение вне функции.

, даже если тип является типом указателя.

единственный способ сделать изменение x внутри функции - это сообщить емуможет быть изменено через ссылки или указатель на тип.

в вашем случае: A * a1 = NULL вызов вашего метода не изменит значение a1 вне testPointer1, поэтому a1 все равно будет NULL после вызова.*

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...