#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 для указателей заключается в том, что вам разрешено изменять значение целевого объекта указателя, но вы не можете изменить адрес, на который указывает указатель.