2016-10-22 5 views
2

Допустим, у меня есть статический метод, который сравнивает два объекта для близкого соответствия и возвращает некоторый уровень достоверности [0,1].Как вернуть дополнительную информацию об отладке из метода?

class Foo 
{ 
    ... 
    static double Compare(const Foo& foo1, const Foo& foo2); 
    ... 
}; 

Теперь мне нужно вернуть дополнительную отладочную информацию, содержащую данные сравнения, в зависимости от настройки в конфигурации. Поскольку эта отладочная информация не будет использоваться на производстве, но только в целях тестирования/отладки, мне было интересно, какой способ ее реализовать.

Я вижу, по крайней мере, три варианта:

1: Создать дополнительный CompareResult класса и хранить уверенность + опциональную информацию там. Не заполняйте дополнительную информацию, если вам это не нужно.

class CompareResult 
{ 
    ... 
private: 
    double confidence_; 
    CompareOptionalInfo compare_optional_info_; 
    ... 
}; 

... 

static CompareResult Compare(const Foo& foo1, const Foo& foo2); 

Это, кажется, самый чистый, но я не уверен, что я должен объединить результат возврата с дополнительной информацией.

2: Используйте выходной переменной (таким образом, нам не нужно, чтобы создать дополнительный класс, но наш метод подписи будет расти немного)

static double Compare(const Foo& foo1, const Foo& foo2, CompareOptionalInfo* out_compare_info = nullptr); 

3: Отдельный метод сравнения с опциональным-инфо метода извлечения ,

static double Compare(const Foo& foo1, const Foo& foo2); 
static CompareOptionalInfo GetCompareOptionalInfo(); 

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

Из вашего опыта, что подходит в мире ООП для возврата необязательной информации (которая будет в основном использоваться только в режиме отладки) из метода?

+0

Планируете ли вы использовать отладчик или распечатывать дополнительную информацию только в режиме отладки? Если вы хотите использовать gdb и использовать такие команды, как 'call Foo :: compare (foo1, foo2)', вы не сможете задать опцию 'compare_optional_info_' опции 1. – Franck

+0

Собираетесь ли вы создать свой производственный код в режиме отладки тест, или вы используете отдельную тестовую программу? – Peter

+0

Это будет вопрос, основанный на мнениях (не по теме). Обычно я хотел бы, чтобы подразделение тестировало мои функции как «черные ящики», что они следуют спецификации и только заботятся о том, что происходит внутри (с точки зрения dbug), если они терпят неудачу. Если есть что-то там, вы действительно хотите провести тестирование единицы, а затем, возможно, можете поместить это в свою собственную функцию, пригодную для тестирования (вариант 1 или 2), и проверить эту функцию отдельно, а не компрометировать «API» с деталями тестирования. Другая возможность заключается в том, что * скомпилировать * информацию о регистрации в функции. – Galik

ответ

1

Вариант 3 не хорошая идея вообще: имеющие функции, зависящие от статических данных не является практичным и может стать даже быть источником ошибок при отладке. Такая конструкция, кроме того, не является потокобезопасной; как бы жалко это было, создать такое ограничение только для цели отладки!

Примеры проблем:

double closest = std::max (Foo::compare (x, y), Foo::compare (y,z)); 
clog << Foo::GetCompareOptionalInfo(); // undefined which info since order of eval 
             // of function parameter is not guaranteed 

double d = Foo::compare (x, y); 
DoSomething();     // what if this one does an unexpected compare ? 
clog << Foo::GetCompareOptionalInfo(); 

Вариант 2 является жизнеспособным решением, но это не очень удобно: он заставляет вас создавать объекты информации, передать их по адресу и т.д.:

Foo::OptionalCompareInfo o1,o2; // cumbersome 
double closest = std::max (Foo::compare (x, y, &o1), Foo::compare (y,z, &o2)); 

Кроме того, вы должны создать эту дополнительную информацию и передать дополнительный аргумент в процессе производства, даже если вы больше не обновляете информацию там (если вы не ставите много дополнительных условных компиляций)!


Вариант 1 отлично! Действуй ! Это действительно использует парадигму ООП и использует чистый дизайн. Практически использовать и не налагать ограничений на свой код, чтобы использовать его.

Все, что вам нужно, чтобы обеспечить некоторую (неявный) функцию преобразования, чтобы использовать свой CompareResult почти как если бы это было double:

class CompareResult 
{ 
public: 
    CompareResult(double d=0.0) : confidence_(d) {}; 
    operator double() { return confidence_; } 
    operator bool() { return confidence_>0.5; } 
private: 
    double confidence_; 
    CompareOptionalInfo compare_optional_info_; 
}; 

online demo

Ваш код продукции будет не зависит от информации отладки , И вы могли бы в вашей отладки ВСЕГДА проследить объяснение того или иного результата сравнения, по крайней мере, если вы храните его:

Пример:

auto result = Foo::compare (x, y) 
if (result) ... // uses automatically the conversion 

auto closest = std::max (Foo::compare (x, y), Foo::compare (y,z)); 
// here you not only know the closest match but could explain it ! 

vector<CompareResult> v; 
... // populate the vector with 10 000 comparison results 
auto r = std::max_element(v.begin(), v.end()); 
    // you could still explain the compare info for the largest value 
    // if you're interested in the details of this single value 
    // how would you do this with option 3 or option 2 ?  

Ok, для самого последнего на работу вы бы также нужен оператор сравнения для вашего дополнительного класса. Но это одна строка кода больше (см. Онлайн-демонстрацию) ;-)

Наконец, может получиться, что ваша «дополнительная информация об отладке» может оказаться более полезной, чем ожидалось, например, чтобы предоставить пользователю дополнительные пояснения по требованию. Все, что вам нужно сделать, - это удалить условный #ifdef DEBUG, окружающий вычисление дополнительной информации.

+1

Местный житель потока делает его потокобезопасным. Очередь буфера или подобная информация об отладке означает обработку нескольких приемлемых; в пределе это становится протоколированием. – Yakk

+0

@ Якк, конечно, совершенно прав, если OP использует GCC> = 4.8 или MSVC> = 2015. Буфер очереди действительно возможен. Но в примере вызова функции с несколькими сравнениями в разных параметрах вы все равно не знаете, в каком порядке они хранятся в очереди. Поэтому вопрос: зачем инвестировать в принятие варианта 3, если вариант 1 уже является очень хорошей альтернативой? – Christophe

+1

Благодарим вас за подробное объяснение! Мне нравится идея превратить «дополнительную информацию об отладке» в дополнительные объяснения по запросу, и я обязательно буду следовать вашим советам. –

0

Я бы использовал второй вариант для его совместимости с отладчиками.

В режиме отладки вы можете добавить дополнительный статический член. Вы должны позаботиться о компоновщике, который не должен его подавлять.

class Foo 
{ 
    private: 
#ifndef NDEBUG 
    CompareOptionalInfo debug_out_compare_info_; 
#endif 

    ... 
    static double Compare(const Foo& foo1, const Foo& foo2, 
     CompareOptionalInfo* out_compare_info = nullptr); 
    ... 
}; 

#ifndef NDEBUG 
CompareOptionalInfo Foo::debug_out_compare_info_; 
#endif 

В БГД, в любой точке останова, вы можете использовать:

call Foo::Compare(foo1, foo2, &Foo::debug_out_compare_info_); 
print Foo::debug_out_compare_info_. ... 
+0

Вам не хватает некоторых NDEBUG, я думаю. – Yakk

+0

Если я хорошо понимаю, ваша идея состоит в том, чтобы использовать в используемом коде только два аргумента (третий по умолчанию - null) и использовать третий аргумент только в сеансе отладчика. Это нормально для ad-hoc-анализа. Однако, если в отладке вы также захотите сделать некоторые записи, вам нужно создать переменные 'CompareOptionalInfo' и передать их адрес. Тогда они останутся в производстве, если вы не добавите много условной компиляции ... – Christophe

+0

@Christophe Все зависит от того, хотите ли вы использовать регистрацию в процессе производства. 'CompareOptionalInfo' также может быть скрыт в вашем классе журнала. Я думаю, вы можете скрыть условные компиляции в некоторых ключевых классах/методах. Более того, в отладчике вы можете попросить «Сравнить» на элементах, которые не были сопоставлены в коде или сравнивались в прошлом/будущем. – Franck

Смежные вопросы