BLE Beacon (Nordic nRF51822) для iPhone (iPhone XR) Сбор данных?

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

Я утверждаю, что хотя это поведение сначала кажется не имеющим смысла, когда вы считаете его более осторожным, оно имеет смысл и является правильным поведением. Во-первых, следует заметить, что категория значений явно является свойством выражений , , а не самих объектов. Это очевидно, так как std::move никогда не создает новый объект, а просто создает выражение rvalue, относящееся к данному объекту. Тогда мы должны понимать, что:

  • Если выражение является lvalue, оно обычно означает, что значение объекта, на которое ссылается выражение, может или будет доступно через одно и то же выражение позже в той же области , Это предположение по умолчанию, когда к объекту обращаются через именованную переменную.
  • Если выражение представляет собой rvalue, это обычно означает, что значение объекта, на которое ссылается выражение, не может или не будет доступно через то же выражение позже в той же области. (Это включает в себя временные значения prvalue, T{} в одном выражении отличается от T{} в более позднем выражении, оба создают анонимные объекты, но оба они различны, поэтому последний не имеет доступа к тому же объекту, что и первый.)

Таким образом, категория значений выражения, ссылающегося на объект, является relative; зависит от конкретного выражения и области видимости. std::move сигнализирует о своем намерении не получать доступ к значению объекта снова в той же области действия, что позволяет вызываемой функции перемещать свое значение из этого объекта. Однако, когда вызываемая функция обращается к имени ссылки rvalue, это значение является постоянным во время вызова функции; функция может перемещать значение из этого объекта в любой точке или вообще не работать, но, во всяком случае, он, вероятно, получит доступ к нему в теле, который после инициализации параметров.

В этом примере :

void f(Foo&& foo) { /* use foo */ }
void g() {
    Foo foo;
    f(std::move(foo));
}

, хотя std::move(foo) в g и параметр foo в вызываемой ссылке относятся к одному и тому же объекту, это значение объекта исчезнет на точки std::move в g, тогда как в f ожидается, что значение этого объекта будет доступно через foo, возможно, несколько раз до конца f.

A аналогичная ситуация существует при вызове ref-квалифицированных функций-членов.

struct Foo {
    void f() &;
    void f() &&;
    void g() && {
        f(); // calls lvalue-qualified f
    }
};
void h() {
    Foo().g();
}

Здесь значение Foo() вот-вот исчезнет из h(); он не будет доступен после полного выражения . Однако в теле Foo::g() он остается постоянным до конца g(); *this надежно обращается к значению одного и того же объекта. Поэтому естественно, что когда g() вызывает f(), он должен вызывать перегрузку, ожидающую lvalue, и f() не должен красть значение *this* из g(), так как g() может все еще хотеть получить к нему доступ .

0
задан Dávid Pásztor 16 January 2019 в 00:18
поделиться