Russian Qt Forum

Программирование => С/C++ => Тема начата: Blackwanderer от Март 16, 2012, 16:48



Название: Эмуляция null-объекта
Отправлено: Blackwanderer от Март 16, 2012, 16:48
Доброго времени суток!
Есть у меня объект "Вектор" (тот, который математический, из линейной алгебры), но при создании объекта я еще не знаю, какой размерности он должен быть. В качестве заглушки я создаю вектор нулевой размерности. Проблема в том, что это некрасиво чисто с эстетической точки зрения, т.к. в линейной алгебре нет понятия вектора нулевой размерности и без дополнительных объяснений/комментариев стороннему человеку непонятно что это за зверь. Опять же использование такого объекта некорректно только с логической точки зрения. С точки зрения языка - это абсолютно обычный объект класса.
Хотелось бы иметь на случай такой заглушки своего рода null-объект, который является особым объектом и который нельзя использовать ни в каких операциях. Понимаю, что средствами языка (по крайней мере в лоб) такого не реализовать. Понимаю, что, возможно, это в принципе нельзя реализовать. И не настаиваю. Задача из разряда хотелок. Но может быть, что-нибудь интересное и удастся придумать.
P.S. Работу с указателями и NULL не предлагать. Это точно также снижает эстетичность программы (приходится писать конструкции типа
Код:
(*vector)[i]
).


Название: Re: Эмуляция null-объекта
Отправлено: mutineer от Март 16, 2012, 16:51
Я не понял задачи


Название: Re: Эмуляция null-объекта
Отправлено: Blackwanderer от Март 16, 2012, 16:55
Я не понял задачи
Хочу заведомо некорректный объект класса причем как с логической точки зрения (объект должен быть некорректен с точки зрения предметной области), так и с точки зрения языка (использование объекта должно вызывать ошибку, исключение и т.д.).


Название: Re: Эмуляция null-объекта
Отправлено: mutineer от Март 16, 2012, 17:27
так и с точки зрения языка (использование объекта должно вызывать ошибку, исключение и т.д.).

Использование какое? разыменование? обращение к методам? передача параметром в фукнцию?

А почему нельзя создать объект тогда, когда будет известна его размерность?


Название: Re: Эмуляция null-объекта
Отправлено: Blackwanderer от Март 16, 2012, 17:38
Использование какое? разыменование? обращение к методам? передача параметром в фукнцию?
Ну, хотя бы обращение к методам.

А почему нельзя создать объект тогда, когда будет известна его размерность?
Потому что этот объект - поле другого, более крупного класса.


Название: Re: Эмуляция null-объекта
Отправлено: mutineer от Март 16, 2012, 17:40
Ну, хотя бы обращение к методам.

Сделай у него методы, которые будут ошибку генерировать:)

Потому что этот объект - поле другого, более крупного класса.
Ииии? Проблема-то в чем?


Название: Re: Эмуляция null-объекта
Отправлено: Igors от Март 16, 2012, 17:46
Хотелось бы иметь на случай такой заглушки своего рода null-объект, который является особым объектом и который нельзя использовать ни в каких операциях.
Вряд ли Вы можете использовать в операциях хоть что-либо с некорректной размерностью (напр множить матрицу 2х2 на 3х3), Тогда к чему цебе "особый объект"? Натыкайте assert'ов - и все дела


Название: Re: Эмуляция null-объекта
Отправлено: m_ax от Март 16, 2012, 17:46
Доброго времени суток!
Есть у меня объект "Вектор" (тот, который математический, из линейной алгебры), но при создании объекта я еще не знаю, какой размерности он должен быть. В качестве заглушки я создаю вектор нулевой размерности. Проблема в том, что это некрасиво чисто с эстетической точки зрения, т.к. в линейной алгебре нет понятия вектора нулевой размерности и без дополнительных объяснений/комментариев стороннему человеку непонятно что это за зверь. Опять же использование такого объекта некорректно только с логической точки зрения. С точки зрения языка - это абсолютно обычный объект класса.
Хотелось бы иметь на случай такой заглушки своего рода null-объект, который является особым объектом и который нельзя использовать ни в каких операциях. Понимаю, что средствами языка (по крайней мере в лоб) такого не реализовать. Понимаю, что, возможно, это в принципе нельзя реализовать. И не настаиваю. Задача из разряда хотелок. Но может быть, что-нибудь интересное и удастся придумать.
P.S. Работу с указателями и NULL не предлагать. Это точно также снижает эстетичность программы (приходится писать конструкции типа
Код:
(*vector)[i]
).


Как вариант: по умолчанию размерность = 1

А пустой вектор вы всё равно не сможете использовать.. компилятор не даст)


Название: Re: Эмуляция null-объекта
Отправлено: m_ax от Март 16, 2012, 17:54
Да, кстати в плюсах уже есть нормальный вектор, с поддержкой всех мат. операций над векторами valarray http://www.cplusplus.com/reference/std/valarray/

Посмотрите как он реализован, прежде чем своё городить)


Название: Re: Эмуляция null-объекта
Отправлено: Blackwanderer от Март 16, 2012, 18:15
Сделай у него методы, которые будут ошибку генерировать:)
Только у одного объекта класса методы ошибку выдавать не могут. Дополнительный флаг и проверка - слишком долго. Наследование и виртуальные функции - не работает inline - слишком долго.

Ииии? Проблема-то в чем?
Объект создается перед входом в конструктор, а размерность известна в лучшем случае хоть и в конструкторе, но через сотню-другую инструкций. Ещё раз, проблема чисто эстетическая, на работу программы это всё никак не влияет.


Название: Re: Эмуляция null-объекта
Отправлено: Blackwanderer от Март 16, 2012, 18:18
Вряд ли Вы можете использовать в операциях хоть что-либо с некорректной размерностью (напр множить матрицу 2х2 на 3х3), Тогда к чему цебе "особый объект"? Натыкайте assert'ов - и все дела
Хотелось бы что бы при взгляде на программу было сразу понятно, что это именно неккоректный вектор-заглушка. Дело в том, что сейчас вполне корректно будет умножаться матрица 0x0 на матрицу 0x0.


Название: Re: Эмуляция null-объекта
Отправлено: Blackwanderer от Март 16, 2012, 18:19
Да, кстати в плюсах уже есть нормальный вектор, с поддержкой всех мат. операций над векторами valarray http://www.cplusplus.com/reference/std/valarray/

Посмотрите как он реализован, прежде чем своё городить)

По сути мой класс - это просто оболочка над stl-контейнером, предоставляющая интерфейс в терминах предметной области.


Название: Re: Эмуляция null-объекта
Отправлено: mutineer от Март 16, 2012, 18:26
Сделай у него методы, которые будут ошибку генерировать:)
Только у одного объекта класса методы ошибку выдавать не могут. Дополнительный флаг и проверка - слишком долго. Наследование и виртуальные функции - не работает inline - слишком долго.

Ииии? Проблема-то в чем?
Объект создается перед входом в конструктор, а размерность известна в лучшем случае хоть и в конструкторе, но через сотню-другую инструкций. Ещё раз, проблема чисто эстетическая, на работу программы это всё никак не влияет.

Ну так сделай поле указателем и создавай объект именно там, где нужно


Название: Re: Эмуляция null-объекта
Отправлено: Blackwanderer от Март 16, 2012, 18:28
Ну так сделай поле указателем и создавай объект именно там, где нужно
См. P.S. Решаем одну эстетическую проблему, получаем другую.


Название: Re: Эмуляция null-объекта
Отправлено: Igors от Март 16, 2012, 18:32
Хотелось бы что бы при взгляде на программу было сразу понятно, что это именно неккоректный вектор-заглушка. Дело в том, что сейчас вполне корректно будет умножаться матрица 0x0 на матрицу 0x0.
Тогда можно попереливать из пустого в порожнее, напр
Код
C++ (Qt)
typedef Vector TEmptyVec;
 
Так нередко делают именно из-за соображений читабельности, чтобы написать TEmptyVec где надо


Название: Re: Эмуляция null-объекта
Отправлено: m_ax от Март 16, 2012, 18:40
Не совсем понимаю в чём эта эстетическая проблема(
Можете кодом пояснить, в чём проблема?


Название: Re: Эмуляция null-объекта
Отправлено: LisandreL от Март 16, 2012, 18:45
Проблема в том, что это некрасиво чисто с эстетической точки зрения, т.к. в линейной алгебре нет понятия вектора нулевой размерности и без дополнительных объяснений/комментариев стороннему человеку непонятно что это за зверь. Опять же использование такого объекта некорректно только с логической точки зрения. С точки зрения языка - это абсолютно обычный объект класса.
А нечего в исходниках вашей программы делать стороннему человеку. Он всё равно ничего не поймёт.


Название: Re: Эмуляция null-объекта
Отправлено: Bepec от Март 16, 2012, 18:52
Черный Странник - вы сейчас несёте чушь.

Вы хотите создать свой новый ( НОВЫЙ) класс с неизвестными ( НЕИЗВЕСТНЫЙ) методами. Выдающим некорректные(НЕКОРРЕКТНЫЙ) данные при (НЕЯСНЫЕ УСЛОВИЯ) условиях.
Который так же будет скрыт (СКРЫТЫЙ) и будет являтся членом класса.

Как вы думаете, человек заглянувший в ваш код поймет НОВЫЙ НЕИЗВЕСТНЫЙ НЕКОРРЕКТНЫЙ с НЕЯСНЫМИ УСЛОВИЯМИ СКРЫТЫЙ класс?

PS бредом страдаете. Исходники ваши должны быть понятны человеку, знающему данный язык написания программы. А не "знать непонятные математические аксиомы и реализующий их только для КРАСИВОСТИ".

PPS С таким подходом у вас появится новый язык программирования - математический непонятный невнятный скрытый некорректный Сиподобный ;)


Название: Re: Эмуляция null-объекта
Отправлено: Igors от Март 16, 2012, 19:03
Бурная реакция непонятна, и, на мой взгляд, неадекватна, каким-то образом показать/намекнуть (хоть самому себе месяц спустя) - это нормально

Код
C++ (Qt)
void UpdateBounds( const Point & pt, Point * box );
void UpdateBounds( const Point & pt, Point box[2] );
 
В первом случае хз что то за бокс, хотя компилятору одинаково


Название: Re: Эмуляция null-объекта
Отправлено: Blackwanderer от Март 16, 2012, 19:11
Не совсем понимаю в чём эта эстетическая проблема(
Можете кодом пояснить, в чём проблема?
Сравните:
Код
C++ (Qt)
for(int i = m_Portrait.Dimension - 1; i > 0; i--)
    for(int j = m_Portrait.IG[i + 1] - 1; j >= m_Portrait.IG[i]; j--)
        vector[m_Portrait.JG[j]] -= m_GGU[j]*vector[i];
 
 
и
Код
C++ (Qt)
for(int i = m_Portrait.Dimension - 1; i > 0; i--)
    for(int j = m_Portrait.IG[i + 1] - 1; j >= m_Portrait.IG[i]; j--)
         (*vector)[m_Portrait.JG[j]] -= m_GGU[j]*(*vector)[i];
 
Лично мне второй вариант кажется более плохим


Название: Re: Эмуляция null-объекта
Отправлено: Blackwanderer от Март 16, 2012, 19:12
Код
C++ (Qt)
typedef Vector TEmptyVec;
 
Так нередко делают именно из-за соображений читабельности, чтобы написать TEmptyVec где надо

Спасибо! Пожалуй лучшее, что можно сделать в данной ситуации.


Название: Re: Эмуляция null-объекта
Отправлено: Blackwanderer от Март 16, 2012, 19:13
Черный Странник - вы сейчас несёте чушь.

Вы хотите создать свой новый ( НОВЫЙ) класс с неизвестными ( НЕИЗВЕСТНЫЙ) методами. Выдающим некорректные(НЕКОРРЕКТНЫЙ) данные при (НЕЯСНЫЕ УСЛОВИЯ) условиях.
Который так же будет скрыт (СКРЫТЫЙ) и будет являтся членом класса.

Как вы думаете, человек заглянувший в ваш код поймет НОВЫЙ НЕИЗВЕСТНЫЙ НЕКОРРЕКТНЫЙ с НЕЯСНЫМИ УСЛОВИЯМИ СКРЫТЫЙ класс?

PS бредом страдаете. Исходники ваши должны быть понятны человеку, знающему данный язык написания программы. А не "знать непонятные математические аксиомы и реализующий их только для КРАСИВОСТИ".

PPS С таким подходом у вас появится новый язык программирования - математический непонятный невнятный скрытый некорректный Сиподобный ;)

В идеале я хочу всего-навсего что-то аналогичное null в Java.


Название: Re: Эмуляция null-объекта
Отправлено: Bepec от Март 16, 2012, 19:23
Каждый выбирает для себя. Успехов!

Себе же я желаю не встречаться с вашим кодом, написанном высокой прозой ;)


Название: Re: Эмуляция null-объекта
Отправлено: BRE от Март 16, 2012, 19:24
В идеале я хочу всего-навсего что-то аналогичное null в Java.
Я не знаю как там null в java, но насколько я понял что ты хочешь, можно попробовать так. Конструктор по умолчанию создает не валидный объект (с нулевой разрядностью, например). Все методы проверяют разрядность и генерируют исключения при работе с таким вектором или отрабатывают assert.
Код
C++ (Qt)
class vector
{
public:
   vector();    // Конструктор по умолчанию, создающий "плохой" объект
   vector( int size );
 
   static vector null;    // Статический объект создаваемый конструктором по умолчанию (плохой)
};
 

Тогда можно использовать такие сравнения:
Код
C++ (Qt)
if( vec != vector::null )
{
}
 


Название: Re: Эмуляция null-объекта
Отправлено: m_ax от Март 16, 2012, 19:31
В идеале я хочу всего-навсего что-то аналогичное null в Java.
Я не знаю как там null в java, но насколько я понял что ты хочешь, можно попробовать так. Конструктор по умолчанию создает не валидный объект (с нулевой разрядностью, например). Все методы проверяют разрядность и генерируют исключения при работе с таким вектором или отрабатывают assert.
Код
C++ (Qt)
class vector
{
public:
   vector();    // Конструктор по умолчанию, создающий "плохой" объект
   vector( int size );
 
   static vector null;    // Статический объект создаваемый конструктором по умолчанию (плохой)
};
 

Тогда можно использовать такие сравнения:
Код
C++ (Qt)
if( vec != vector::null )
{
}
 


А если просто включить метод, типа bool isEmpty() ?
Код
C++ (Qt)
if (vector.isEmpty())
  ...
else
  ...
 

Не совсем понимаю в чём эта эстетическая проблема(
Можете кодом пояснить, в чём проблема?
Сравните:
Код
C++ (Qt)
for(int i = m_Portrait.Dimension - 1; i > 0; i--)
    for(int j = m_Portrait.IG[i + 1] - 1; j >= m_Portrait.IG[i]; j--)
        vector[m_Portrait.JG[j]] -= m_GGU[j]*vector[i];
 
 
и
Код
C++ (Qt)
for(int i = m_Portrait.Dimension - 1; i > 0; i--)
    for(int j = m_Portrait.IG[i + 1] - 1; j >= m_Portrait.IG[i]; j--)
         (*vector)[m_Portrait.JG[j]] -= m_GGU[j]*(*vector)[i];
 
Лично мне второй вариант кажется более плохим

И что? А как собственно это соотносится с те, что вы хотите то?
 


Название: Re: Эмуляция null-объекта
Отправлено: BRE от Март 16, 2012, 19:32
А если просто включить метод, типа bool isEmpty() ?
+ isValid()


Название: Re: Эмуляция null-объекта
Отправлено: Blackwanderer от Март 16, 2012, 19:37
Я не знаю как там null в java, но насколько я понял что ты хочешь, можно попробовать так. Конструктор по умолчанию создает не валидный объект (с нулевой разрядностью, например). Все методы проверяют разрядность и генерируют исключения при работе с таким вектором или отрабатывают assert.
Увы, это будет слишком долго. У векторов размерность десятки тысяч, и подобная проверка где-нибудь в operator[] существенно замедлит программу.


Название: Re: Эмуляция null-объекта
Отправлено: Blackwanderer от Март 16, 2012, 19:41
И что? А как собственно это соотносится с те, что вы хотите то?
Это я показал, почему не хочу работать с указателями.


Название: Re: Эмуляция null-объекта
Отправлено: Igors от Март 16, 2012, 19:46
Увы, это будет слишком долго. У векторов размерность десятки тысяч, и подобная проверка где-нибудь в operator[] существенно замедлит программу.
То да. Также бывает конструктор по умолчанию оказывается существенно затратным


Название: Re: Эмуляция null-объекта
Отправлено: m_ax от Март 16, 2012, 19:49
И что? А как собственно это соотносится с те, что вы хотите то?
Это я показал, почему не хочу работать с указателями.

Ну это я понял..
Так вы приведёте пример кода, где вы видите эту вашу эстетическую проблему?   


Название: Re: Эмуляция null-объекта
Отправлено: BRE от Март 16, 2012, 19:50
Увы, это будет слишком долго. У векторов размерность десятки тысяч, и подобная проверка где-нибудь в operator[] существенно замедлит программу.
Хорошо, пробуем так:
Код
C++ (Qt)
class vector_base
{
public:
virtual void method1() = 0;
virtual void method2() = 0;
};
 
class null_vector : public vector_base
{
public:
virtual void method1(); // посылает исключение
virtual void method2(); // посылает исключение
};
 
class valid_vector : public vector_base
{
public:
valid_vector( int size ) { ... }
 
virtual void method1(); // выполняет действие
virtual void method2(); // выполняет действие
};
 
// =========================================================
 
class vector
{
public:
vector() : m_vec( new null_vector ) {}
vector( int size ) : m_vec( new valid_vector( size ) ) {}
 
void setup( int size )
{
delete m_vec;
m_vec = new valid_vector( size );
}
 
void medhod1()
{
m_vec->method1();
}
 
void medhod2()
{
m_vec->method2();
}
 
private:
vector_base *m_vec;
};
 


Название: Re: Эмуляция null-объекта
Отправлено: Igors от Март 16, 2012, 20:41
Напр vector_base это std::valarray о котором упоминал m_ax. Тогда чтобы передать весь его ф-ционал в Ваш vector - надо очень много делегироваться. А если сделать член public - обращения раздует изрядно.


Название: Re: Эмуляция null-объекта
Отправлено: BRE от Март 16, 2012, 20:44
Напр vector_base это std::valarray о котором упоминал m_ax. Тогда чтобы передать весь его ф-ционал в Ваш vector - надо очень много делегироваться. А если сделать член public - обращения раздует изрядно.
А что делать. Хотим скорости и что бы тогда проверялось, а тогда нет.



Название: Re: Эмуляция null-объекта
Отправлено: m_ax от Март 16, 2012, 22:56
Увы, это будет слишком долго. У векторов размерность десятки тысяч, и подобная проверка где-нибудь в operator[] существенно замедлит программу.
Хорошо, пробуем так:
Код
C++ (Qt)
class vector_base
{
public:
virtual void method1() = 0;
virtual void method2() = 0;
};
 
class null_vector : public vector_base
{
public:
virtual void method1(); // посылает исключение
virtual void method2(); // посылает исключение
};
 
class valid_vector : public vector_base
{
public:
valid_vector( int size ) { ... }
 
virtual void method1(); // выполняет действие
virtual void method2(); // выполняет действие
};
 
// =========================================================
 
class vector
{
public:
vector() : m_vec( new null_vector ) {}
vector( int size ) : m_vec( new valid_vector( size ) ) {}
 
void setup( int size )
{
delete m_vec;
m_vec = new valid_vector( size );
}
 
void medhod1()
{
m_vec->method1();
}
 
void medhod2()
{
m_vec->method2();
}
 
private:
vector_base *m_vec;
};
 

Или можно написать просто маленький классик "затычку", вместо иерархии векторов:
Код
C++ (Qt)
struct base_state
{
   virtual void police() = 0;
};
 
struct null_state : public base_state
{
   virtual void police() { throw exception; } // Кидаем исключения
};
 
struct valid_state : public base_state
{
   virtual void police() {}  // Ничего не делаем, просто пропускаем.
};
 
class vector
{
public:
vector() : m_state( new null_state ) {}
vector( int size ) : m_state( new valid_state) {}
 
void setup( int size )
{
delete m_state;
m_state = new valid_state;
}
 
void medhod1()
{
m_state->police();
               ....
               ....
}
 
void medhod2()
{
   m_state->police();
           ....
           ....
}
 
private:
   base_state    *m_state;
};
 


Название: Re: Эмуляция null-объекта
Отправлено: BRE от Март 16, 2012, 23:01
Но все таки, такие вещи должны отслеживаться на этапе разработки и отлавливаться механизмами типа assert еще во время отладки. Тащить это в релиз, IMHO, избыточно.


Название: Re: Эмуляция null-объекта
Отправлено: m_ax от Март 16, 2012, 23:07
Но все таки, такие вещи должны отслеживаться на этапе разработки и отлавливаться механизмами типа assert еще во время отладки. Тащить это в релиз, IMHO, избыточно.


Это да, но у меня почему-то такое ощущение, что Чёрный странник что-то другое имел в виду.. Я вот так до конца и не понял, какого поведения от вектора он хотел получить(


Название: Re: Эмуляция null-объекта
Отправлено: BRE от Март 16, 2012, 23:16
У меня такое же ощущение. Подождем, что он скажет про наши перлы, может будет понятней. :)

2 Черный странник а еще лучше в коде покажи: "Хочу вот так". Не обязательно что бы это компилировалось.


Название: Re: Эмуляция null-объекта
Отправлено: Blackwanderer от Март 17, 2012, 07:06
В чем проблема
Код
C++ (Qt)
class Solver
{
public:
Solver(): x(){
// Why we create some vector at this point? Why you choose such dimension for vector?
// We don't know anything about it. And we don't understad what is vector of zero dimension.
// Is it valid? Can we use it? Will be it used somewhere?
....
// Only now we know dimension of vector
x = Vector(dimension);
}
private:
Vector x;
}
 

Что хочу:
Код
C++ (Qt)
class Solver
{
public:
Solver(): x(null){
// It is obviously that x is null-object. We don't know anything about it.
// Any action with x should crash program. Only assigment allowed.
....
// Now we know dimension of vector
x = Vector(dimension);
}
private:
Vector x;
}
 

На данный момент больше всего мне понравился совет от Igors
Код
C++ (Qt)
typedef Vector NullVector
 
class Solver
{
public:
Solver(): x(NullVector()){
// It will not crash, but at least it is clear that vector x is null-object.
....
// Now we know dimension of vector
x = Vector(dimension);
}
private:
Vector x;
}
 

С виртуализацие будет работать. Это достаточно известный Null Object Pattern. Но проблема в том, что тогда перестанет работать inline, что крайне отрицательно скажется на скорости. А поскольку это всего лишь хотелка, то скорость превыше красоты.
P.S. В теге {code=cpp-qt} можно корректно писать кириллицей?


Название: Re: Эмуляция null-объекта
Отправлено: BRE от Март 17, 2012, 08:25
Но мне так и не понятно, почему ты не хочешь использовать assert во всех методах, с проверкой на нулевую размерность?
Проверка будет работать только для debug-сборки, в релизе от нее не останется и следа. И будешь гарантировано получать по рукам при попытке использовать такой вектор.


Название: Re: Эмуляция null-объекта
Отправлено: Akon от Март 17, 2012, 10:36
Цитировать
Хочу заведомо некорректный объект класса причем как с логической точки зрения (объект должен быть некорректен с точки зрения предметной области) ...
ОК, приведите пример некорректного вектора с т.з. линейной алгебры.

ИМХО, все что вам нужно - Vector::isValid(). Обобщенное решение задачи (когда у типа нет специального null значения (специального метода isValid()) - boost::optional.


Название: Re: Эмуляция null-объекта
Отправлено: Blackwanderer от Март 17, 2012, 16:51
Но мне так и не понятно, почему ты не хочешь использовать assert во всех методах, с проверкой на нулевую размерность?
Проверка будет работать только для debug-сборки, в релизе от нее не останется и следа. И будешь гарантировано получать по рукам при попытке использовать такой вектор.
Кстати да, что-то я ступил. В купе с советом от Igors про typedef будет почти близко к желаемому. Благодарствую.