Возврат указателя на аргумент intent (in)

#c #pointers #fortran #language-lawyer #immutability

#c #указатели #fortran #язык-юрист #неизменность

Вопрос:

Я пытаюсь лучше понять разницу между const C / C и intent(in) Fortran в контексте классов.

C : если я const являюсь неявным this аргументом функции-члена и возвращаю ссылки на члены this , эти ссылки должны быть const T* . Таким const образом, это относится не только к области действия вызова функции, но также распространяется на все ссылки, «созданные» в этом вызове функции.

Fortran: если я intent(in) this аргумент функции-члена intent(in) , то применяется только к области видимости функции-члена. Я не могу изменять this внутри функции-члена, но я могу вернуть ссылку и изменить this снаружи.

Если у меня есть следующий более или менее эквивалентный код для класса Counter на Fortran и C , чтобы проверить это, и это кажется правильным.

 #include <iostream>


class Counter {
    int val{};

public:
    auto next()
    {
        return val  ;
    };

    const auto raw() const
    {
        const auto ptr = amp;val;
        return ptr;
    };
};

int main()
{
    Counter c{};
    std::cout << c.next() << "n";
    std::cout << c.next() << "n";

    auto ptr = c.raw();
    // does not compile, as it is expected
    *ptr = 0;
    std::cout << c.next() << "n";

    return 0;
}
  
 module counter_mod
    implicit none(type, external)
    private
    public :: Counter_t

    type :: Counter_t
        private
        integer :: val = 0
    contains
        procedure :: next
        procedure :: raw
    end type

contains

    integer function next(this)
        class(Counter_t), intent(inout) :: this
        next = this%val
        this%val = this%val   1
    end function

    function raw(this) result(res)
        class(Counter_t), target, intent(in) :: this
        integer, pointer :: res
        ! This would be forbidden
        ! this%val = 5
        res => this%val
    end function
end module

program test_raw
    use counter_mod, only: Counter_t
    implicit none(type, external)

    type(Counter_t), target :: c
    integer, pointer :: ptr

    write(*, *) c%next()
    write(*, *) c%next()

    ptr => c%raw()
    ptr = 0
    write(*, *) c%next()
end program
  

Комментарии:

1. вы можете вернуть неконстантную ссылку / указатель из const метода, но не на член, потому что они являются постоянными

2. в чем вопрос?

3. Мой вопрос в том, правильно ли то, что я написал.

4. тогда вы, по сути, задаете два вопроса. Корректен ли код C и корректен ли код fortran. Кроме одной строки, код C выглядит нормально, я ничего не могу сказать о Fortran, в прошлый раз, когда я его использовал, он выглядел совершенно по-другому

5. @mcocdawc Чтобы получить больше информации, я перенаправил ваш вопрос на сайт Fortran discourse , который несколько больше ориентирован на открытые вопросы и обсуждения. Я думаю, будет здорово, если вы также добавите туда комментарии (чтобы читатели также более четко понимали намерение <— каламбур :).

Ответ №1:

В c вам не нужно возвращать a const pointer , вы можете просто вернуть a const reference . Это типичная реализация getter, например:

метод const означает, что свойства экземпляра не будут изменены методом.

 class Counter {
    int val{};

public:
    auto next()
    {
        return val  ;
    };

    const int amp;getVal const
    {
        return val;
    };
};
  

В приведенном выше примере средство получения также может возвращать копию val . (в этом случае нет необходимости возвращать постоянную ссылку).

Комментарии:

1. > В приведенном выше примере средство получения также может возвращать копию val . Я знаю, но мой член на самом деле намного больше.

Ответ №2:

Прочитав комментарии и ответы, касающиеся части моего вопроса на C , и проконсультировавшись со стандартом Fortran 2008, я думаю, что смогу ответить на свой собственный вопрос:

C : невозможно (без таких хитрых трюков, как const_cast ) создать T* указатель или Tamp; ссылку на const T переменную типа T . Указатели / ссылки const также должны быть на. Следовательно: if this является const аргументом нашей функции-члена, нам не разрешается возвращать не const указатели или ссылки.

 intamp; getVal() const {return val;};
  
 int* getVal() const {return amp;val;};
  

оба не будут компилироваться. Итак, объявив this as const , мы можем предоставить нашим членам доступ только для чтения. (И благодаря @Jean-Marc Volle я буду использовать первую версию.)

Fortran: основная проблема Fortran заключается в том, что нет указателей на const ( const T* ) , а есть только const указатели ( T* const ) . Таким образом, невозможно предоставить доступ только для чтения с помощью указателя на компоненты типа (члены класса в C ). Оставшийся вопрос заключается в разнице между const и intent(in) и если возможно вернуть возможно изменяющуюся ссылку на объект (или его компоненты) intent(in) .

В стандарте Fortran 2008 5.3.10 говорится:

Атрибут INTENT (IN) для фиктивного аргумента, не являющегося указателем, указывает, что он не должен ни определяться, ни становиться неопределенным во время вызова и выполнения процедуры. Атрибут INTENT (IN) для фиктивного аргумента указателя указывает, что во время вызова и выполнения процедуры его связь не должна изменяться, за исключением того, что она может стать неопределенной, если цель освобождается иначе, чем через указатель (16.5.2.5).

Если я правильно интерпретирую это, не разрешается изменять intent(in) объект, но можно вернуть (возможно) изменяющуюся ссылку.

Комментарии:

1. Значение 5.3.10 для указателей заключается в том, что вам разрешено изменять значение целевого объекта указателя, но вы не можете изменить адрес, на который указывает указатель.