Как реализовать оператор-> для пользовательского класса UniquePtr в C++?

Я пытаюсь написать свою собственную реализацию unique_ptr на C++, и вот мой заголовочный файл UniquePtr:

#include <iostream>

template <typename T>
class UniquePtr
{
    T* ptr;

public:
    UniquePtr(T* _ptr);

    UniquePtr(const UniquePtr& other) = delete;
    UniquePtr& operator=(const UniquePtr& other) = delete;

    UniquePtr(UniquePtr&& dying) noexcept;
    UniquePtr& operator=(UniquePtr&& dying) noexcept;

    T& operator*();
    const T& operator*() const;

    /*??? operator->() 
    {

    }*/

    /*??? operator->() const
    {

    }*/

    ~UniquePtr();
};

Я не понимаю, какой оператор-> должен возвращать. Я знаю, что вызов в форме uniquePtr->member преобразуется в (*uniquePtr).member, но это все равно не помогает мне понять, что должен возвращать оператор->.

Я понимаю, что операторы — это, по сути, функции со специальным именем, поэтому мы можем думать о -> как о функции, которая принимает только один аргумент — указатель на объект (который получают все функции-члены). Однако меня немного смущает то, как перевод вызова uniquePtr->member должен диктовать способ его переопределения в классе (каким должен быть тип возвращаемого значения).

Может ли кто-нибудь объяснить, как реализовать оператор -> для этого специального класса UniquePtr и почему он реализован именно таким образом?

Это не ответ на мой вопрос:

Каковы основные правила и идиомы перегрузки операторов?

Дубликат ДЕЙСТВИТЕЛЬНО отвечает на ваш вопрос. Если вы выполните поиск operator-> на этой странице, вы найдете короткий абзац, объясняющий, как работает перегрузка operator->. Он даже использует пример типа указателя, который говорит, что вы должны вернуть value_type*, как и в вашем случае.

Weijun Zhou 29.06.2024 05:09

@WeijunZhou, перестань зацикливаться на себе! Даже пользователь, ответивший на мой вопрос, сказал, что предоставленный вариант, который якобы отвечает на него, не очень хорошо объясняет оператор ->. Зная, что я могу найти ответ на СВОЙ вопрос, хотя и сказал, что не могу. Оставайтесь на своей полосе, пожалуйста.

user25687822 29.06.2024 12:45

Я согласен, что тон не идеален, и прошу прощения, если вас обидел. Мне следовало прокомментировать так: «Я верю в предложенный обман, и ссылка там отвечает на ваш вопрос, можете ли вы отредактировать свой вопрос, чтобы объяснить, почему это не так, вместо того, чтобы просто заявить, что это не так? Это может помочь получить ваш вопрос снова открыт». Кстати, я не голосовал за закрытие вашего вопроса.

Weijun Zhou 29.06.2024 14:17
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я знаю, что вызов в форме uniquePtr->member переводится в (*uniquePtr).member

Так ведет себя встроенный оператор ->. Если вместо этого выбрана перегрузка, компилятор преобразует

uniquePtr->member

к

(uniquePtr.operator->())->member

и это будет сделано рекурсивно для нового оператора ->.

Вы хотите, чтобы это привело к (uniquePtr.ptr)->member, который после расширения встроенного -> будет (*(uniquePtr.ptr)).member. Итак, вы хотите, чтобы ваш operator->() просто вернулся ptr. Тип возвращаемого значения должен соответствовать const-квалификации перегрузки.

Также обратите внимание, что поведение -> при выборе перегрузки оператора, которое я объяснил выше, является особенным для -> и отличается от поведения любого другого бинарного оператора. Это не то, что вы можете вывести из общего правила перегрузки бинарных операторов.

Спасибо за ответ! Хотя я все еще немного в замешательстве. Почему компилятор переводит uniquePtr->member в (uniquePtr.operator->())->member? То есть из одного оператора -> мы получаем два оператора ->. Имеет ли это смысл?

user25687822 29.06.2024 00:58

Извините, но я не считаю, что мой вопрос является дубликатом, поскольку предоставленный «дубликат» вопрос НЕ отвечает на мой.

user25687822 29.06.2024 01:05

@user25687822 user25687822 Я не закрыл ваш вопрос. Это был другой пользователь. Однако этот связанный вопрос считается каноническим дубликатом для всех вопросов по объяснениям базовой перегрузки операторов, даже если объяснения -> в ответах кажутся не очень хорошими.

user17732522 29.06.2024 01:10

@user25687822 user25687822 Компилятор переводит это таким образом, потому что такого поведения требует стандарт. uniquePtr->member сначала переводится в (эквивалент) (uniquePtr.operator->())->member. Если возвращаемый тип operator->() является объектом, который также имеет operator->(), выражение второй раз преобразуется в (uniquePtr.operator->().operator->())->member. Этот перевод в вызовы operator->() повторяется до тех пор, пока один из operator->() не вернет необработанный указатель (типа SomeType *). [что, по сути, и сказал пользователь 17732522].

Peter 29.06.2024 03:56

Другие вопросы по теме