Nonconst lvalue ссылка - PullRequest
       85

Nonconst lvalue ссылка

1 голос
/ 06 апреля 2020

Я создаю неориентированный граф, и каждый раз, когда я добавляю соседа A к узлу BI, я должен добавить также узел B в качестве соседа A, но мой подход не работает.

Non-const lvalue reference to type 'Element *' cannot bind to a temporary of type 'Element *'

class Element
{
    std::vector<Element *> m_neighbours;
private:

public:
    void addNeighbour(Element*& neighbour)
    {
        m_neighbours.push_back(neighbour);
        neighbour->addNeighbour(this);
    }
};
  1. Что происходит?
  2. Лучший способ ее решить?

Ответы [ 2 ]

1 голос
/ 06 апреля 2020

Указатель this определен как prvalue , а ваша функция принимает lvalue. Язык запрещает такую ​​привязку по разным причинам . Вы не изменяете данный указатель, поэтому просто передайте его по значению, а не по ссылке.

void addNeighbour(Element* neighbour);

вместо

void addNeighbour(Element*& neighbour);
1 голос
/ 06 апреля 2020

Чтобы понять, в чем проблема, давайте представим, что вместо этого вы написали этот код:

void addNeighbour(Element*& neighbour)
{
    m_neighbours.emplace_back(neighbour);
    neighbour->addNeighbour(this);
    neighbour = nullptr; // <--- This is new
}

Теперь подумайте о том, что происходит, когда вы делаете этот вызов:

neighbour->addNeighbour(this);

вызов функции передается в this по ссылке, что означает «пожалуйста, не стесняйтесь переназначить this». И затем в вызове функции последняя строка действительно пытается переназначить neighbour на nullptr. Но это проблема, потому что вы не можете написать

this = nullptr; // Error!

, потому что this - это значение.

Самое простое решение здесь - не брать параметр по ссылке, так как вы ничего не делать, если вам действительно нужна ссылка. Просто наберите Element*, сказав: «Пожалуйста, передайте мне копию нужного вам указателя».

(Независимо - ваш код доставит вам неприятности, потому что вызов A->addNeighbour(B) вызовет B->addNeighbour(A), который вызывает A->addNeighbour(B), который вызывает B->addNeighbour(A) и т. д. c., пока вы не выбросите свой стек вызовов. Вы должны добавить проверку здесь, чтобы убедиться, что, если Element уже записано, вы не Не добавляйте его во второй раз. Вы можете сделать m_neighbours std::unordered_set вместо std::vector для этой цели.)

...