Не работает преобразование типов указателей на члены класса.
От: Slowspeed  
Дата: 11.06.10 14:38
Оценка:
Попытка вызова OutputDebugString вызывает ошибку доступа к памяти.
Почему?
class A
{
public:

    char str[255];
};

void f(A &a, char *(A::*pStr))
{
    OutputDebugStringA(a.*pStr);
}

int _tmain(int argc, _TCHAR* argv[])
{
    A a;

    strncpy(a.str, "\nArray\n", 255);

    f(a, (char *(A::*))&A::str);

    return 0;
}

добавил разметку — Кодт
Re: Не работает преобразование типов указателей на члены кла
От: Vamp Россия  
Дата: 11.06.10 14:48
Оценка:
S>Почему?
А что за странное преобразование типов ты устроил? Естественно у тебя падает приложение, потому что ты передаешь объект совсем другого типа, и обманываешь компилятор.


class A
{
public:

char str[255];
};

void f(A &a, char (A::*)[255])
{
}

int main()
{
A a;

f(a, &A::str);

return 0;
}
Да здравствует мыло душистое и веревка пушистая.
Re: Не работает преобразование типов указателей на члены кла
От: achp  
Дата: 11.06.10 14:48
Оценка:
Здравствуйте, Slowspeed, Вы писали:

S>Попытка вызова OutputDebugString вызывает ошибку доступа к памяти.

S>Почему?

Потому что A::str имеет тип char[255], а не char*. По-моему, это очевидно.
Re: Не работает преобразование типов указателей на члены кла
От: Кодт Россия  
Дата: 11.06.10 14:53
Оценка:
Здравствуйте, Slowspeed, Вы писали:

S>Попытка вызова OutputDebugString вызывает ошибку доступа к памяти.

S>Почему?

Потому что фактический тип члена — char[255], а у тебя указатель на член типа char*
Соответственно, первые четыре символа трактуются как указатель на строку.

Кстати, если компилятор ругается на несовместимость типов, то надо исправлять типы, а не затыкать реинтерпрет-кастом. Кривой реинтерпрет — дорога в ад.

В крайнем случае, можно было бы приводить к указателю на односимвольный массив. Для работы со строками размер массива не важен.
А ещё лучше — заменить голое замыкание ->* функцией char*(A*)

http://codepad.org/LeDWo0N1
struct A
{
  char x[20];
  char y[10];
  char const* z;
};

void print( boost::function<char const* (A const*)> f )
{
  A a = { "hello", "the", "world" };
  cout << f(&a) << endl;
}

int main()
{
  print( boost::bind(&A::x, _1) );
  print( boost::bind(&A::y, _1) );
  print( boost::bind(&A::z, _1) );
}
Перекуём баги на фичи!
Re[2]: Не работает преобразование типов указателей на члены
От: Slowspeed  
Дата: 11.06.10 15:20
Оценка:
Да, вижу, ступил.
В более общем виде задача у меня такая:
Есть список структур, в каждой структуре несколько символьных массивов разного размера.
Надо пройти по списку несколько раз и для каждой структуры вызвать некоторую функцию обработки строки.
Причем в каждом проходе обрабатывать другой массив.

т.е.

struct TS
{
char s1[255];
char s2[512];
...
}

В первом проходе обработать все строки s1, во втором все строки s2, итд.
Я планировал передавать функции обработки указатель на структуру и указатель на член класса,
меняя указатель на член класса перед каждым проходом.
Но из-за разной длины строк я не могу вторым параметром функции сделать массив, поэтому хотел сделать
его каким-нибудь указателем. Можно, конечно, задать параметром массив фиксированной длины и приводить
к его типу указатель на член класса перед каждым проходом, но хотелось бы что-нибудь поизящней.
Re[3]: Не работает преобразование типов указателей на члены
От: Кодт Россия  
Дата: 11.06.10 16:09
Оценка:
Здравствуйте, Slowspeed, Вы писали:

S>Есть список структур, в каждой структуре несколько символьных массивов разного размера.


Указатели на члены позволяют сочетать фактические объекты-наследники и фактические члены-предки, в том числе, в условиях непростого наследования (со сдвигом баз).

Если этого не нужно, — если структуры все POD, — то можно сделать просто, на смещениях:
Сишный подход
struct A { char x[10], y[20], z[30]; } aaa[10];
struct B { char p[100], q[200]; } bbb[20];

// сишный подход
void run_the_array(void* objects, size_t width, size_t count, size_t offset, void(*f)(char*))
{
  for(int i=0; i!=count; ++i)
  {
    char* object = (char*)objects + i*width;
    char* member = object + offset;
    f(member);
  }
}
...
run_the_array(aaa, sizeof(A), _countof(aaa), _offsetof(A,x[0]), print);
run_the_array(bbb, sizeof(B), _countof(bbb), _offsetof(B,q[0]), print);

size_t a_offsets[3] = { _offsetof(A,x[0]), _offsetof(A,y[0]), _offsetof(A,z[0]) };
for(i=0; i!=3; ++i)
  run_the_array(aaa, sizeof(A), _countof(aaa), a_offsets[i]);


Если нет нужды перебирать массивы в цикле:
Шаблонный подход (для каждого указателя своя подстановка)
std::for_each(aaa, aaa+_countof(aaa), boost::bind(print, boost::bind(&A::x, _1)));
std::for_each(aaa, aaa+_countof(aaa), boost::bind(print, boost::bind(&A::y, _1)));

http://codepad.org/yONnEDMz — пример
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.