Кавычке было нужно: использование Препроцессора является плохой практикой OO

Простая эвристика проверяет значения, меньшие или равные sqrt(sqrt(n)) для входа n. Следовательно, сложность этого алгоритма будет "choose 2 from sqrt(sqrt(n))" = O(sqrt(n)).

17
задан Brian Tompsett - 汤莱恩 8 July 2016 в 15:38
поделиться

12 ответов

Henry Spencer написал работу, названную #ifdef, Продуманный Вредный .

кроме того, сам Bjarne Stroustrup, в главе 18 его книги Дизайн и Эволюция C++ , осуждает использование препроцессора и хочет устранить его полностью. Однако Stroustrup также распознает необходимость #ifdef директивы и условной компиляции и продолжает иллюстрировать, что нет никакой хорошей альтернативы для нее в C++.

Наконец, Pete Goodliffe, в главе 13 его книжного Ремесла Кода: Практика Написания Превосходного Кода , дает пример, как, даже когда используется для его исходной цели, #ifdef может сделать путаницу из Вашего кода.

Hope это помогает. Однако, если Ваши коллеги не будут слушать разумные аргументы во-первых, я сомневаюсь, что книжные кавычки помогут убедить их ;)

25
ответ дан 30 November 2019 в 10:04
поделиться

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

0
ответ дан 30 November 2019 в 10:04
поделиться

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

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

1
ответ дан 30 November 2019 в 10:04
поделиться

IMO важно дифференцироваться между #if и #define. Оба могут быть полезными, и оба могут злоупотребиться. Мой опыт состоит в том, что #define, более вероятно, злоупотребится, чем #if.

я потратил 10 + годы, делая C и программирование на C++. В проектах я продолжил работать (коммерчески доступное программное обеспечение для DOS / Unix / Macintosh / Windows), мы использовали #if и #define, прежде всего, чтобы заниматься проблемами переносимости кода.

я провел достаточно времени, работая с C++ / MFC, чтобы учиться терпеть не мочь #define, когда он злоупотребляется - которому я верю для имения место в MFC приблизительно 1996.

я затем потратил 7 + годы, работая над проектами Java. Я не могу сказать, что пропустил препроцессор (хотя я несомненно пропускал вещи как перечислимые типы и шаблоны / дженерики, которые Java не имел в то время).

я работал в C# с 2003. Мы сделали интенсивное использование #if и [Условное выражение ("ОТЛАДКА")] для наших сборок отладки - но #if является просто более удобным, и немного более эффективным способом сделать то же самое, которое мы сделали в Java.

Продвижение, мы начали готовить наш базовый механизм к Silverlight. В то время как все, что мы делаем, могло обойтись без #if, это - меньше работы с #if, что означает, что мы можем потратить опции добавляющего большего количества времени, которые просят наши клиенты. Например, у нас есть класс значения, который инкапсулирует системный цвет для устройства хранения данных в нашем базовом механизме. Ниже первые несколько строк кода. Из-за подобия между Системой. Рисование. Цвет и Система. Windows. Медиа. Цвет, #define наверху получает нас большая функциональность в нормальной.NET и в Silverlight, не копируя код:

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
#if SILVERLIGHT
using SystemColor = System.Windows.Media.Color;
#else
using SystemColor = System.Drawing.Color;
#endif

namespace SpreadsheetGear.Drawing
{
    /// <summary>
    /// Represents a Color in the SpreadsheetGear API and provides implicit conversion operators to and from System.Drawing.Color and / or System.Windows.Media.Color.
    /// </summary>
    public struct Color
    {
        public override string ToString()
        {
            //return string.Format("Color({0}, {1}, {2})", R, G, B);
            return _color.ToString();
        }

        public override bool Equals(object obj)
        {
            return (obj is Color && (this == (Color)obj))
                || (obj is SystemColor && (_color == (SystemColor)obj));
        }
        ...

нижняя строка для меня - то, что существует много функций языка, которые могут злоупотребиться, но это не достаточно хорошая причина пропустить эти функции или сделать строгие правила, запрещающие их использование. Я должен сказать, что перемещение в C# после программирования в Java так долго помогает мне ценить это, потому что Microsoft (Anders Hejlsberg) была более готова обеспечить функции, которые не могли бы обратиться к преподавателю вуза, но которые делают меня более продуктивным в моем задании и в конечном счете позволяют мне создать лучший виджет в ограниченное время, которое кто-либо с датой поставки имеет.

2
ответ дан 30 November 2019 в 10:04
поделиться

В c# / VB.NET я не сказал бы его зло.

, Например, когда сервисы окон отладки, я вставил следующее Основное так, чтобы, когда в Режиме отладки, я могу выполнить сервис как приложение.

    <MTAThread()> _
    <System.Diagnostics.DebuggerNonUserCode()> _
    Shared Sub Main()


#If DEBUG Then

        'Starts this up as an application.'

        Dim _service As New DispatchService()
        _service.ServiceStartupMethod(Nothing)
        System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite)

#Else

        'Runs as a service. '

        Dim ServicesToRun() As System.ServiceProcess.ServiceBase
        ServicesToRun = New System.ServiceProcess.ServiceBase() {New DispatchService}
        System.ServiceProcess.ServiceBase.Run(ServicesToRun)

#End If

    End Sub

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

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

РЕДАКТИРОВАНИЕ: Ре: первый комментарий. Я не добираюсь, как тот пример соединяется здесь. Проблема состоит в том, что препроцессор неправильно используется, не, что это является злым.

я дам Вам другой пример. У нас есть приложение, которое делает проверку версии между клиентом и сервером на запуске. В разработке мы часто имеем различные версии и не хотим делать проверку версии. Действительно ли это является злым?

я предполагаю то, что я пытаюсь сказать, то, что препроцессор не является злым, изменяя поведение программы. Проблема состоит в том, что кто-то неправильно использует его. Что не так с высказыванием этого? Почему Вы пытаетесь отклонить функцию языка?

Намного более позднее РЕДАКТИРОВАНИЕ : FWIW: я не использовал директивы препроцессору для этого за несколько лет. Я делаю условия применения. UserInteractive с определенным аргументом устанавливают ("-c" = Консоль), и аккуратный прием, от которого я поднял где-нибудь здесь на ТАК, чтобы не заблокировать приложение, но все еще ожидать ввода данных пользователем.

Shared Sub Main(args as string[])
  If (Environment.UserInteractive = True) Then
    'Starts this up as an application.
    If (args.Length > 0 AndAlso args[0].Equals("-c")) Then 'usually a "DeriveCommand" function that returns an enum or something similar
      Dim isRunning As Boolean = true
      Dim _service As New DispatchService()
      _service.ServiceStartupMethod(Nothing)
      Console.WriteLine("Press ESC to stop running")
      While (IsRunning)
        While (Not (Console.KeyAvailable AndAlso (Console.ReadKey(true).Key.Equals(ConsoleKey.Escape) OrElse Console.ReadKey(true).Key.Equals(ConsoleKey.R))))
           Thread.Sleep(1)
         End While                        
         Console.WriteLine()
         Console.WriteLine("Press ESC to continue running or any other key to continue shutdown.")
         Dim key = Console.ReadKey();
         if (key.Key.Equals(ConsoleKey.Escape))
         {
           Console.WriteLine("Press ESC to load shutdown menu.")
           Continue
         }
         isRunning = false
      End While
      _service.ServiceStopMethod()
    Else
      Throw New ArgumentException("Dont be a double clicker, this needs a console for reporting info and errors")
    End If
  Else

    'Runs as a service. '
    Dim ServicesToRun() As System.ServiceProcess.ServiceBase
    ServicesToRun = New System.ServiceProcess.ServiceBase() {New DispatchService}
    System.ServiceProcess.ServiceBase.Run(ServicesToRun)
  End If
End Sub
2
ответ дан 30 November 2019 в 10:04
поделиться

Одна проблема с #ifdef препроцессора состоит в том, что они эффективно копируют количество скомпилированных версий, которые в теории необходимо протестировать полностью так, чтобы можно было сказать, что поставленный код является правильным.

  #ifdef DEBUG
  //...
  #else
  //...

хорошо, теперь я могу произвести версию "Отладки" и версию "Выпуска". Это хорошо для меня, я всегда делаю это, потому что я имею утверждения и отлаживаю трассировки, которые только выполняются в отладочной версии.

, Если кто-то приезжает и записи (реальный пример)

  #ifdef MANUALLY_MANAGED_MEMORY
  ...

И они пишут любимую оптимизацию, которую они распространяют к четырем или пяти различным классам, затем внезапно у Вас есть ЧЕТЫРЕ возможных способа скомпилировать Ваш код.

, Если только у Вас есть другой код #ifdef-dependant затем, у Вас будет ВОСЕМЬ возможных версий для генерации, и что является более тревожащим, ЧЕТЫРЕ из них будут возможными версиями выпуска.

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

Это - причина, почему я думаю, поскольку политика, весь #ifdef кроме того для Отладки/Версии выпуска должен быть временный , т.е. Вы делаете эксперимент в коде разработки, и Вы решите, скоро, если это останется так или иначе.

4
ответ дан 30 November 2019 в 10:04
поделиться

"Препроцессор является воплощением зла и причиной всей боли на земле" - Robert (Гуру OO)

9
ответ дан 30 November 2019 в 10:04
поделиться

Используя #if вместо МОК или некоторого другого механизма для управления другой функциональностью на основе конфигурации, вероятно, нарушение Единственного Принципа Ответственности, который является ключом для 'современных' проектов OO. Вот обширный ряд статей о принципах разработки OO.

, Так как части в различных разделах #if по определению интересуются различными аспектами системы, Вы теперь связываете детали реализации по крайней мере двух различных компонентов в цепочку зависимости Вашего кода, который использует #if.

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

В Вашем исходном случае, необходимо будет помнить существование #if и взять его во внимание любое время любое эти три изменения компонентов относительно возможных побочных эффектов повреждающегося изменения.

2
ответ дан 30 November 2019 в 10:04
поделиться

Bjarne Stroustrap предоставляет свой ответ (в целом, не характерный для МОК) здесь

Так, что случилось с использованием макросов?

(выборка)

Макросы не повинуются объему C++ и вводят правила. Это часто - причина тонких и not-so-subtle проблем. Следовательно, C++ обеспечивает альтернативы, которые соответствуют лучше остальной части C++, такого как подставляемые функции, шаблоны и пространства имен.

3
ответ дан 30 November 2019 в 10:04
поделиться

Директивы препроцессору в C# очень ясно определили и случаи практических применений. Те, которые Вы конкретно говорите о, названный условными директивами, используются для управления, какие части кода компилируются и которые не являются.

существует очень важное различие между не компиляцией частей кода и управлением, как Ваш граф объектов соединен проводом через МОК. Давайте посмотрим на реальный пример: XNA. При разработке игр XNA, которые Вы планируете развернуть и в Windows и в XBox 360, Ваше решение будет обычно иметь по крайней мере две платформы, которые можно переключить между в IDE. Будет несколько различий между ними, но одно из тех различий будет то, что платформа XBox 360 определит условный символ XBOX360, который можно использовать в исходном коде со следующей идиомой:

#if (XBOX360)
// some XBOX360-specific code here
#else
// some Windows-specific code here
#endif

Вы могли, конечно, факторизовать эти различия с помощью шаблона разработки Стратегии и управления через МОК, какой инстанцируют, но условная компиляция предлагает по крайней мере три главных преимущества:

  1. Вы не поставляете код, в котором Вы не нуждаетесь.
  2. Вы видите различия между определенным для платформы кодом для обеих платформ в законном контексте того кода.
  3. наверху нет никакой косвенности. Соответствующий код компилируется, другой не и вот именно.
12
ответ дан 30 November 2019 в 10:04
поделиться

По моему скромному мнению, Вы говорите о C и C++, не о практике OO в целом. И C не Объектно-ориентирован. На обоих языках препроцессор на самом деле полезен. Просто используйте его правильно.

я думаю, что этот ответ принадлежит C++ FAQ: [29.8] Вы говорите, что препроцессор является злым? .

Да, это точно, что я говорю: препроцессор является злым.

Каждый #define макрос эффективно создает новое ключевое слово в каждом исходном файле и каждом объеме, пока тот символ не #undef d. Препроцессор позволяет Вам создать #define символ, который всегда заменяется независимый от эти {...} объем, где тот символ появляется.

Иногда нам нужен препроцессор, такой как #ifndef/#define обертка в каждом заголовочном файле, но нужно избежать, когда Вы можете. "Зло" не означает "никогда использование". Вы будете использовать злые вещи иногда, особенно когда они будут "меньшим из двух зла". Но они являются все еще злыми :-)

я надеюсь, что этот источник является достаточно авторитетным :-)

14
ответ дан 30 November 2019 в 10:04
поделиться

Поддержка предварительной обработки в C# очень минимальна.... нахождение на грани бесполезного. Это является Злым?

Препроцессор что-нибудь, чтобы сделать с OO? Конечно, это для конфигурации сборки.

, Например, у меня есть облегченная версия и проверсия моего приложения. Я мог бы хотеть исключить некоторый код облегченного withour, имеющего необходимость обращаться к созданию очень похожих версий кода.

я не мог бы хотеть поставлять облегченную версию, которая является про версией с различными флагами во время выполнения.

Tony

2
ответ дан 30 November 2019 в 10:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: