Инициализация массива внутри класса
От: Sergey Россия  
Дата: 26.03.13 07:13
Оценка: -1 :))) :)
Инициализация массива внутри класса

Задача, необходимо иметь массив указателей на элементы класса.
Пример решения:

typedef struct {
  int a;
  int *p;
}Tarray;

class TCtest 
{
public:
   TCtest(void)
   {
    initarray();
   }
   ~TCtest(void){}
   void initarray(void)
   { 
    const Tarray arr[]=
    {  
     {1,&a1},
     {2,&a2},
     {3,&a3},
    };
    ar=(Tarray*)arr;
   }
int a1,a2,a3;
Tarray * ar;
};

int main(void)
{
TCtest c1;
TCtest c2;
c1.a1 = 11;
c1.a2 = 22;
c1.a3 = 33;
c2.a1 = 44;
c2.a2 = 55;
c2.a3 = 66;
printf("A1=%d A2=%d A3=%d\r\n",*c1.ar[0].p,*c1.ar[1].p,*c1.ar[2].p);
printf("A1=%d A2=%d A3=%d\r\n",*c2.ar[0].p,*c2.ar[1].p,*c2.ar[2].p);
return(0);
}

Вывод программы
Output:
A1=11 A2=22 A3=33
A1=44 A2=55 A3=66


Какие ещё могут быть варианты?
Какие недостатки решения?
Re[4]: Инициализация массива внутри класса
От: Evgeny.Panasyuk Россия  
Дата: 26.03.13 13:52
Оценка: 4 (1)
Здравствуйте, rusted, Вы писали:

EP>>
EP>>    for(auto &&v : foo.bar)
EP>>        cout << "n=" << v.n << ",*p=" << *v.p << endl;
EP>>

R>А для чего в этом примере rvalue-ссылку использовать? Чем обычная хуже?

Это "не совсем" rvalue — это так называемая "universal reference" — она биндится ко всему — и к reference, и к rvalue.
Конкретно в этом примере без разницы, что auto, что auto&, что auto&&, что const auto&.
Re[4]: Инициализация массива внутри класса
От: rg45 СССР  
Дата: 26.03.13 14:10
Оценка: 4 (1)
Здравствуйте, rusted, Вы писали:

R>Здравствуйте, Evgeny.Panasyuk, Вы писали:


EP>>
EP>>    for(auto &&v : foo.bar)
EP>>        cout << "n=" << v.n << ",*p=" << *v.p << endl;
EP>>


R>А для чего в этом примере rvalue-ссылку использовать? Чем обычная хуже?


В данном случае тип "auto&&" как раз и разворачивается в "обычную" lvalue ссылку. Убедиться в этом можно, если на место auto подставить тип явно, мы получим ошибку компиляции:
    for(Pair &&v : foo.bar) //error: cannot bind 'Pair' lvalue to 'Pair&&'
        cout << "n=" << v.n << ",*p=" << *v.p << endl;
--
Справедливость выше закона. А человечность выше справедливости.
Re: Инициализация массива внутри класса
От: Vain Россия google.ru
Дата: 27.03.13 06:47
Оценка: :)
Здравствуйте, Sergey, Вы писали:

S>Какие недостатки решения?

у неправильного решения нет недостатков
адреса нестатических локальных переменных функций (стековых переменных) нельзя использовать за функцией, т.к. их распределяет (аллоцирует/освобождает) компилятор, а время их жизни ограничено их областью видимости
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re: Инициализация массива внутри класса
От: Evgeny.Panasyuk Россия  
Дата: 26.03.13 07:26
Оценка:
Здравствуйте, Sergey, Вы писали:

S>
S>typedef struct {
S>  int a;
S>  int *p;
S>}Tarray;
S>


это атавизм.

S>Какие недостатки решения?


UB.
Re: Инициализация массива внутри класса
От: saf_e  
Дата: 26.03.13 10:54
Оценка:
Здравствуйте, Sergey, Вы писали:

S>Инициализация массива внутри класса


S>Задача, необходимо иметь массив указателей на элементы класса.

S>Пример решения:

S>[ccode]

S>typedef struct {
S> int a;
S> int *p;
S>}Tarray;

S>Какие ещё могут быть варианты?

S>Какие недостатки решения?

S>class TCtest 
S>{
S>public:
S>   TCtest(void)
S>   {
S>    //initarray();
S>   }
S>   ~TCtest(void){}
     struct initarray{
S>   initarray(void)
S>   { 
S>    const static Tarray arr[]=
S>    {  
S>     {1,&a1},
S>     {2,&a2},
S>     {3,&a3},
S>    };
S>    ar=(Tarray*)arr;
S>   }
};
static initarray _init;
S>int a1,a2,a3;
S>static Tarray * ar;
S>};
в .cpp:
TCtest::initarray TCtest::_init;


так хоть UB не будет.

Из недостатков -- неконсистентно, при любом изменении класса, летит структура. К сожалению в С++ нет автоматических способов такое сделать.
Re[2]: Инициализация массива внутри класса
От: saf_e  
Дата: 26.03.13 11:11
Оценка:
Здравствуйте, saf_e, Вы писали:

overquoting
Забыл добавить: все это не будет компилироваться
З.Ы. Кнопку редактирования не нашел
Re[2]: Инициализация массива внутри класса
От: Evgeny.Panasyuk Россия  
Дата: 26.03.13 12:34
Оценка:
Здравствуйте, saf_e, Вы писали:

_>К сожалению в С++ нет автоматических способов такое сделать.


http://liveworkspace.org/code/3vNkxu$0
#include <iostream>
#include <ostream>
using namespace std;

struct Pair
{
    int n;
    int *p;
};
struct Foo
{
    int a=11, b=22;
    Pair bar[2] = {{0,&a},{1,&b}};
};

int main()
{
    Foo foo;
    for(auto &&v : foo.bar)
        cout << "n=" << v.n << ",*p=" << *v.p << endl;
}
Re[3]: Инициализация массива внутри класса
От: saf_e  
Дата: 26.03.13 12:41
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, saf_e, Вы писали:


_>>К сожалению в С++ нет автоматических способов такое сделать.


EP>http://liveworkspace.org/code/3vNkxu$0

EP>
EP>#include <iostream>
EP>#include <ostream>
EP>using namespace std;

EP>struct Pair
EP>{
EP>    int n;
EP>    int *p;
EP>};
EP>struct Foo
EP>{
EP>    int a=11, b=22;
EP>    Pair bar[2] = {{0,&a},{1,&b}};
EP>};

EP>int main()
EP>{
EP>    Foo foo;
EP>    for(auto &&v : foo.bar)
EP>        cout << "n=" << v.n << ",*p=" << *v.p << endl;
EP>}
EP>


Я имел в виду, что при изменении layout'a класса, придется дописывать руками соотв. структуру.

Круто
Выглядит, не как С++ Т.е. теперь уже можно размазать код конструктора по объявлению класса...
В данном контексте я бы ожидал что выражение: &a будет соотв. int Foo::*, а не int *
Re[3]: Инициализация массива внутри класса
От: rusted Беларусь  
Дата: 26.03.13 12:52
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>
EP>    for(auto &&v : foo.bar)
EP>        cout << "n=" << v.n << ",*p=" << *v.p << endl;
EP>


А для чего в этом примере rvalue-ссылку использовать? Чем обычная хуже?
Re[4]: Инициализация массива внутри класса
От: Evgeny.Panasyuk Россия  
Дата: 26.03.13 13:59
Оценка:
Здравствуйте, saf_e, Вы писали:

_>Я имел в виду, что при изменении layout'a класса, придется дописывать руками соотв. структуру.


А я не знаю что именно хочет получить ТС. Вообще этот массив держать per-object не обязательно — можно разрулить в compile-time.

_>Круто

_>Выглядит, не как С++

http://www.stroustrup.com/C++11FAQ.html

Surprisingly, C++11 feels like a new language: The pieces just fit together better than they used to and I find a higher-level style of programming more natural than before and as efficient as ever.

Re: Инициализация массива внутри класса
От: Кодт Россия  
Дата: 26.03.13 20:16
Оценка:
Здравствуйте, Sergey, Вы писали:

S>Инициализация массива внутри класса


S>Задача, необходимо иметь массив указателей на элементы класса.

<>

Если нужны указатели на члены данного экземпляра, — то напрашивается очевидный вариант: std::vector.
Размещать массив где-то на стеке — это UB (элементарно же: по выходу из конструктора стек разрушается), а где-то в статическом хранилище — это на грани UB (несколько одновременно живущих объектов будут перезаписывать этот массив, что сломает логику, а при известном невезении — получим ещё и висячие указатели на члены разрушенного объекта).
Делать свой рукодельный массив — а оно надо? Возни много, за памятью следить...
Либо завести тип "массив" (а не указатель).
struct TArray
{
    int n;
    int** a;
};

class CTest
{
public:
    int y, z, x;
    struct XYZ { int* a[3]; } xyz;
    std::vector<int*> uvw;

    CTest()
    {
        xyz = {{&x,&y,&z}};
        uvw = {{&x,&y,&z}};
    }
    TArray arr() { return TArray{3, rand() ? xyz.a : &uvw.front() }; }
};

int main()
{
    CTest p,q;
    p.x = 1; p.y = 2; p.z = 3;
    q.x = 4; q.y = 5; q.z = 6;

    printf("%d %d\n", *p.arr().a[0], *q.arr().a[0]);
}

(здесь я не позаботился о копировании и присваивании — понятно же, что копировать/присваивать эти векторы нельзя, — надо оставлять их привязанными к родному объекту).

Если нужны указатели на члены класса, — это немножко другая история.
Напомню: указатель на член может быть связан с любым (другим) экземпляром — но только данного класса или его наследника.
class CTest;
typedef int CTest::* CTestIntField;

struct CTestFields
{
  int n;
  CTestIntField* a;
};

class CTest
{
public:
  int y, z, x;

  static CTestFields const& fields()
  {
    static const CTestIntField a[] = { &CTest::x, &CTest::y, &CTest::z };
    static const CTestFields f = { ARRAY_SIZE(a), a };
    return f;
  }
};

int main()
{
  CTestFields const& f = CTest::fields();
  CTest p; p.x=1;
  CTest q; q.x=4;
  printf("%d %d", p.*f[0], q.*f[0]); // постфиксный оператор [] имеет приоритет перед инфиксным .* - скобки не нужны
}
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.