LINUX.ORG.RU

С++ размышление об указателях на члены-переменные структур/классов

 


0

1

Добрый день. Нормально ли считается использовать обычные указатели на члены-переменные структур/классов, например так:

#include <iostream>

using namespace std;

struct A {
  int i;
};

void f(int *i) { cout << dec << *i << " " << hex << (long)i << endl; }
void f(int &i) { cout << dec << i << " " << hex << (long)&i << endl; }

void f(A *pa, int A::*am) {
  cout << dec << pa->*am << " " << hex << (long)&(pa->*am) << endl;
}

void f(A *pa) { cout << dec << pa->i << " " << hex << (long)&(pa->i) << endl; }
void f(A &ra) { cout << dec << ra.i << " " << hex << (long)&(ra.i) << endl; }

int main() {
  A a{55};

  // Номально ли делать так
  f(&a.i);
  f(a.i);

  // Или лучше так (чем лучше?)
  f(&a, &A::i);

  // Или может вообще лучше так
  f(&a);
  f(a);

  return 0;
}

// Вывод:
// 55 7ffcb727e274
// 55 7ffcb727e274
// 55 7ffcb727e274
// 55 7ffcb727e274
// 55 7ffcb727e274
★★★★★

Последнее исправление: cetjs2 (всего исправлений: 1)

Конечно. А указатель на поле может понадобится для обхода массива каких-то структур, например, или в какой-то шаблонной обёртке доступа к полю. Одно другому не является полной заменой.

xaizek ★★★★★
()

A a{55};

f(&a.i);

а это точно c++?

// Или может вообще лучше так

думаю лучше вот так: a.f()

anonymous
()
Ответ на: комментарий от xaizek

А если сравнивать

f(A *pa, int A::*am);

// и

void f(int *i);
void f(int &i);

Что лучше? Не вижу ни одного преимущества первой формы (понимаю, когда у нас есть указатель на не статическую функцию-член, но в случае члена переменной где тут удобство).

rumgot ★★★★★
() автор топика
Последнее исправление: rumgot (всего исправлений: 1)
Ответ на: комментарий от rumgot

тут из C++ use std, cout и перегрузка функций.

Если это C++, то почему не использовать методы структуры?

anonymous
()
Ответ на: комментарий от crutch_master

Это понятно. Но с точки зрения частоты использования?

rumgot ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Это C++, не неси ерунды. И не уводи тему в сторону. Мне нужны ответы именно на поставленные вопросы.

rumgot ★★★★★
() автор топика

Конечно же ссылка:

void f(int &i)  
f(a.i);

f(&a, &A::i);

Это извращение.

f(a);

Если нужна функция для распечатывания значения класса, то лучше засунуть её во внутрь класса в виде метода

ox55ff ★★★★★
()
Последнее исправление: ox55ff (всего исправлений: 1)

На таком примере не воспроизведётся. Нужна ситуация, когда знаем какой метод вызвать, но объекта ещё нет

DllMain
()
Ответ на: комментарий от rumgot

C++ это не только компилятор и расширение файла, но еще и стиль/методы программирования. Пока что у вас C :)

anonymous
()
Ответ на: комментарий от anonymous

Извини. Я не хочу в этот спор.

rumgot ★★★★★
() автор топика
Ответ на: комментарий от crutch_master

А сейчас придёт Царь

У тебя наблюдается довольно пугающая степень фиксации на нем, я бы на твоем месте задумался :)

curufinwe ★★★★★
()

Смысл вопроса непонятен.

Обычный указатель (скажем на int) вы используете когда вам нужно что-то сделать с каким-то int-ом и неважно каким именно. Лежит ли этот int как поле в какой-то структуре или это элемент вектора int-ов, или это одиночный int на стеке – без разницы. У вас есть просто операция f(int *p) которая что-то делает с любым int-ом. Ну, скажем:

void ensure_not_negative(int *p) {
  if(*p < 0) *p = 0;
}

Указатель на член класса используется когда вам нужно производить какие-то операции не над произвольным int-ом, а над int-ом, который является членом конкретного класса. При этом вы не знаете, с каким именно экземпляром класса вам придется работать. Но вам важно, что работать придется именно с членом этого класса. Например:

struct Point {
  int x_;
  int y_;
};

void ensure_not_negative(Point * instance, int Point::*member) {
  if(instance->*member < 0) instance->*member = 0;
}
...
std::vector<Point> points{...};
for(auto & p : points) {
  ensure_not_negative(&p, &Point::x_);
  ...
  ensure_not_negative(&p, &Point::y_);
}

Ну и да, представление указателей на члены у разных компиляторов разное и не факт, что указатель на член может быть скастован в void* (и тем более в long).

eao197 ★★★★★
()
Ответ на: комментарий от rumgot

В таком варианте лучше это:

void f(int &i);

раз всё равно конкретное поле и нужно.

xaizek ★★★★★
()
Ответ на: комментарий от curufinwe

У тебя наблюдается довольно пугающая степень фиксации на нем

Да просто держу в курсе, чтобы не расслаблялись:)

crutch_master ★★★★★
()
Ответ на: комментарий от curufinwe

фиксации

У тебя фиксация на фиксации.

Интерес к психоанализу - интересный материал для психоанаиза.

anonymous
()

Если чужое API, требующее указатели, то да. Если вчё твоё, то у тебя проблема с дизайном.

invy ★★★★★
()

Нормально ли считается использовать обычные указатели на члены-переменные структур/классов

Да, вполне нормально, если это не нарушает инкапсуляцию.

DELIRIUM ☆☆☆☆☆
()
Ответ на: комментарий от invy

++

не увидел ни одного упоминания std::function в треде

UVV ★★★★★
()

Как говорили выше, в целом всё ок. Но нужно учитывать, что это может сломаться при использовании указателей на структуры с атрибутом packed. По-крайней gcc об этом предупреждает.

Если структура упакована, то выравнивание её членов может быть произвольным, а функции рассчитывают, что принимаемые аргументы будут нормально выравнены.

Ivan_qrt ★★★★★
()
Ответ на: комментарий от Ivan_qrt

Но нужно учитывать, что это может сломаться при использовании указателей на структуры с атрибутом packed.

атрибут packed - не стандарт + это не точно, но указатель на член класса тоже может сломаться в таком случае

next_time ★★★★★
()
Ответ на: комментарий от invy

нет ни каких особых проблем с дизайном, наоборот

  1. в С++ считается предпочтительным передавать всё по ссылке, а не по значению, а так как согласно ООП всё лежит в объектах, то передача ссылок на члены-переменные структур/классов является общепринятой нормой, отступление от которой скорее является странностью

  2. в языках, произошедших от С++ (java, C#) - вообще всё, кроме примитивных типов, передаётся именно по указателю

единственное отступление от общепринятой практики у ТС лишь в том, что в С++ он передаёт адрес по указателю, а т.к. указатель, передаваемый в функцию, с т.з. вызывющего кода всегда константный, разница лишь в том, что передаваемое значение может быть nullptr, что иногда удобно

next_time ★★★★★
()
Ответ на: комментарий от next_time

атрибут packed - не стандарт + это не точно, но указатель на член класса тоже может сломаться в таком случае

Если в такой форме

f(A *pa, int A::*am);

то тоже может сломаться?

rumgot ★★★★★
() автор топика
Последнее исправление: rumgot (всего исправлений: 2)
Ответ на: комментарий от next_time

единственное отступление от общепринятой практики у ТС лишь в том, что в С++ он передаёт адрес по указателю, а т.к. указатель, передаваемый в функцию, с т.з. вызывющего кода всегда константный, разница лишь в том, что передаваемое значение может быть nullptr, что иногда удобно

Можешь пожалуйста подробней? Не распарсил.

rumgot ★★★★★
() автор топика
Ответ на: комментарий от next_time

А, ты в том смысле, что в случае указателя можно еще nullptr передать при необходимости, а в случае ссылки там обязана быть конкретная сущность?

rumgot ★★★★★
() автор топика
Последнее исправление: rumgot (всего исправлений: 2)
Ответ на: комментарий от DllMain

И что? Ты нашел один пост четырехлетней! давности и сделал вывод о фиксации? Да ты видимо профессиональный психолог. И это ж, серьезно, надо было среди тучи моих постов отрыть :)

Эту энергию бы да в мирное русло, динамо машину там крутить и снабжать энергией город, например.

curufinwe ★★★★★
()
Последнее исправление: curufinwe (всего исправлений: 2)
Ответ на: комментарий от curufinwe

Оправдывайся теперь)

И это ж, серьезно, надо было среди тучи моих постов отрыть :)

Ты серьёзно думаешь, что я целенаправлено искал что-то подобное, а не наткнулся случайно?

DllMain
()
Ответ на: комментарий от DllMain

Оправдывайся теперь)

От чего? Я и сейчас могу сказать, что против царя я ничего не имею. А его срачи зачастую заставляют задуматься об очень интересных вещах. Но я не захожу в каждую тему и не пишу «а царь то, а царь сё», как человек, которого я призывал задуматься.

Ты серьёзно думаешь, что я целенаправлено искал что-то подобное, а не наткнулся случайно?

Нет, это была шутка.

curufinwe ★★★★★
()
Ответ на: комментарий от curufinwe

А его срачи зачастую заставляют задуматься об очень интересных вещах

Например?

Но я не захожу в каждую тему и не пишу «а царь то, а царь сё», как человек, которого я призывал задуматься

Крутчмастер грешит этим, да. Но это скорее юморок такой.

А вообще - забей, мне просто показалось забавным твоё сообщение в том топике, если рассматривать его уже после прочтения ответа крутчмастеру. Больше ничего

DllMain
()
Ответ на: комментарий от DllMain

Например?

Например - как писать программы, как разные парадигмы программирования соотносятся между собой, какие подходы эффективнее и лучше. Еще раз - заставляет задуматься об этом. Не больше и не меньше.

curufinwe ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.