Nano Hash - криптовалюты, майнинг, программирование

Запутанное поведение вокруг обязательного отказа от копирования/перемещения

Играя с RVO, я столкнулся со следующей проблемой, и я не могу понять ее.

#include <iostream>
struct A {
    A* p = this;
};

A func()
{
    return A();
}

int main()
{
    A a = A();
    std::cout << "address of a: " << &a << " - a.p = " << a.p << std::endl;

    A b = func();          
    std::cout << "address of b: " << &b << " - b.p = " << b.p << std::endl;
}

Результат:

address of a: 0x7ffe5b11b7a0 - a.p = 0x7ffe5b11b7a0

address of b: 0x7ffe5b11b790 - b.p = 0x7ffe5b11b770

С a все в порядке. Однако обратите внимание, что b.p на самом деле не указывает на b, как если бы он указывал на другой объект.

Я использую gcc 8.3.0, который поддерживает C++17. Насколько я понимаю, начиная с С++ 17, RVO является обязательным, и инициализация из значения prvalue (т.е. A b = func();) также должна вызывать обязательное исключение. Следовательно, теоретически для инициализации b должен вызываться только один конструктор, поэтому p не должен указывать ни на что другое, кроме b. Может ли кто-нибудь объяснить мне, что здесь происходит?

Примечание: инициализация p в конструкторе по умолчанию вместо использования инициализации члена по умолчанию не меняет поведение.

Я еще немного поиграл с этим и понял, что определение конструктора по умолчанию И любой из следующих специальных функций заставляет p указывать на b, как и ожидалось:

  • деструктор
  • конструктор перемещения
  • оператор присваивания перемещения
  • конструктор копирования

Вместо того, чтобы помочь мне понять проблему, это еще больше запутало меня...

Кстати, я наблюдал точно такое же поведение с gcc 11.0.0 и clang 11.0.0 (используя Wandbox), так что это вряд ли ошибка.

16.06.2020

  • Чтобы получить больше информации и точек данных, попробуйте добавить конструктор по умолчанию, который сбрасывает this в std::cout, и посмотрите, что это вам даст. 16.06.2020
  • Действительно, я сделал это в качестве теста, и он всегда был равен p. 16.06.2020
  • eel.is/c++draft/class.temporary#3. предложение-1 16.06.2020
  • Интересно, что если конструктор копирования определен как удаленный, то он ведет себя так, как ожидалось. Изменить: правило, связанное с cpplearner, объясняет это. 16.06.2020
  • @eeroika Вот демонстрация. При удалении удаленных определений адреса меняются. Это совершенно странно. 16.06.2020
  • Небольшой тривиальный объект, здесь применяется тот же ответ " title=" зависит ли поведение гарантированного удаления копии от существования определенного пользователем"> stackoverflow.com/questions/48879226/ (вероятно, дубликат). 16.06.2020
  • @StoryTeller-UnslanderMonica Хорошая находка, не помню своих ответов ;-). Просто отметим, что правило, вероятно, было мотивировано передачей объектов в регистры, а здесь мы явно требуем, чтобы они находились в памяти для обращения. 16.06.2020
  • Благодаря cpplearner и StoryTeller. Действительно похоже на дубликат. Итак, если я правильно понимаю, это тот случай, когда компилятор может создать временное, и p указывает на это временное. 16.06.2020
  • @StoryTeller-UnslanderMonica Касательная тема: верите ли вы, что страница cppreference об исключении копии является неточным w.r.t. этот временный объект угловой случай? В частности, раздел Обязательное исключение операций копирования/перемещения, который, по-видимому, охватывает исключение возвращаемого значения исключительно с точки зрения передачи нематериализованного значения, тогда как, как указано в вашем связанном ответе, временный может действительно материализоваться при некоторых обстоятельствах. 16.06.2020
  • @dfri - не столько неточное, сколько неполное. Правильно утверждать, что никакая ценность не материализуется (в отличие от упущенной). Но это не распространяется на то, когда должна/может произойти материализация. 16.06.2020

Новые материалы

Кластеризация: более глубокий взгляд
Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

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

Частный метод Python: улучшение инкапсуляции и безопасности
Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

Как я автоматизирую тестирование с помощью Jest
Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..