Запрещение создания временных объектов

Конечно, замените <%! counter++; %> на архитектуру производителя-потребителя событий, где бизнес-уровень уведомляется о необходимости увеличения счетчика, он реагирует соответствующим образом и уведомляет докладчиков, чтобы они обновляли представления. Применяется ряд транзакций базы данных, поскольку в будущем нам нужно будет узнать новое и старое значение счетчика, который увеличил его и с какой целью. Очевидно, что сериализация задействована, поскольку слои полностью развязаны. Вы сможете увеличить ваш счетчик на RMI, IIOP, SOAP. Но требуется только HTML, который вы не реализуете, поскольку это такой мирский случай. Ваша новая цель - достичь 250 шагов в секунду на вашем новом блестящем E7, 64-гигабайтном операционном сервере.

У меня более 20 лет в программировании, большинство проектов проваливаются до секстета: Возможность повторного использования Возможность OO-возможности Отказоустойчивость. Возможность обеспечения работоспособности даже необходима. Другие проекты, управляемые людьми, которые заботились только о функциональности, были чрезвычайно успешными. Кроме того, жесткая структура объектов, внедренная слишком рано в проекте, делает код неспособным адаптироваться к резким изменениям в спецификациях (так же гибким).

Поэтому я рассматриваю в качестве промедления активность определения «слоев» "или избыточные структуры данных либо в начале проекта, либо когда это не требуется. & NBSP; [/ д2]

26
задан Naveen 27 May 2009 в 20:44
поделиться

6 ответов

Редактировать: Как отмечает j_random_hacker, можно заставить пользователя объявить именованный объект, чтобы снять блокировку.

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

// take out a lock:
if (m_multiThreaded)
{
    CSingleLock c(&m_criticalSection, TRUE);
}

// do other stuff, assuming lock is held

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

Другая вероятная ошибка:

 CSingleLock *c = new CSingleLock(&m_criticalSection, TRUE);

 // do other stuff, don't call delete on c...

Что заставит вас спросить: «Могу ли я как-нибудь помешать пользователю моего класса распределить его по куче»? На что ответ будет таким же.

В C ++ 0x будет еще один способ сделать все это, используя лямбды. Определите функцию:

template <class TLock, class TLockedOperation>
void WithLock(TLock *lock, const TLockedOperation &op)
{
    CSingleLock c(lock, TRUE);
    op();
}

Эта функция фиксирует правильное использование CSingleLock. Теперь позвольте пользователям делать это:

WithLock(&m_criticalSection, 
[&] {
        // do stuff, lock is held in this context.
    });

Это намного сложнее для пользователя испортить. Сначала синтаксис выглядит странно, но [& amp;], за которым следует блок кода, означает «Определить функцию, которая не принимает аргументов, и если я ссылаюсь на что-либо по имени, и это имя чего-то вне (например, локальная переменная содержащий функцию) позвольте мне получить доступ к ней по неконстантной ссылке, чтобы я мог ее изменить.)

13
ответ дан Daniel Earwicker 19 July 2019 в 15:17
поделиться

Компилятор не должен запрещать создание временных объектов, ИМХО.

Особенно в таких случаях, как сокращение вектора, вам действительно нужен временный объект для создания.

std::vector<T>(v).swap(v);

Хотя это немного сложно, но пересмотр кода и модульное тестирование должны решить эти проблемы.

В противном случае, вот решение одного бедняка:

CSingleLock aLock(&m_criticalSection); //Don't use the second parameter whose default is FALSE

aLock.Lock();  //an explicit lock should take care of your problem
2
ответ дан aJ. 19 July 2019 в 15:17
поделиться

Я вижу, что за 5 лет никто не придумал самое простое решение:

#define LOCK(x) CSingleLock lock(&x, TRUE);
...
void f() {
   LOCK(m_criticalSection);

И теперь используют только этот макрос для создания замков. Больше нет никаких шансов создать временных! Это дает дополнительное преимущество, заключающееся в том, что макрос может быть легко дополнен для выполнения любого вида проверки в сборках отладки, например, для обнаружения неподходящей рекурсивной блокировки, записи файла и строки блокировки, и многого другого.

-1
ответ дан Paavo 19 July 2019 в 15:17
поделиться

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

Но в вашем конкретном случае это действительно может избегать. Это потому, что C ++ делает одно (странное) различие в отношении временных объектов: Бесплатные функции не могут принимать неконстантные ссылки на временные объекты. Итак, чтобы избежать появления и исчезновения блокировок, просто переместите код блокировки из конструктора CSingleLock в бесплатную функцию (которую вы можете подружить, чтобы не показывать внутренние компоненты как методы) :

class CSingleLock {
    friend void Lock(CSingleLock& lock) {
        // Perform the actual locking here.
    }
};

Разблокировка по-прежнему выполняется в деструкторе.

Использование:

CSingleLock myLock(&m_criticalSection, TRUE);
Lock(myLock);

Да, это немного сложнее для написания. Но теперь компилятор пожалуется, если вы попробуете:

Lock(CSingleLock(&m_criticalSection, TRUE));   // Error! Caught at compile time.

Поскольку параметр неконстантной ссылки Lock () не может связываться с временным.

Возможно, удивительно, что методы класса могут работать с временными объектами - поэтому ] Lock () должна быть бесплатной функцией. Если вы отбросите спецификатор friend и параметр функции в верхнем фрагменте, чтобы сделать Lock () методом, то компилятор с радостью позволит вам написать:

CSingleLock(&m_criticalSection, TRUE).Lock();  // Yikes!

MS COMPILER NOTE : Версии MSVC ++ до Visual Studio .NET 2003 некорректно разрешали функциям связываться с неконстантными ссылками в версиях до VC ++ 2005. Это поведение было исправлено в VC ++ 2005 и выше .

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

CSingleLock(&m_criticalSection, TRUE).Lock();  // Yikes!

MS COMPILER NOTE : Версии MSVC ++ до Visual Studio .NET 2003 некорректно разрешали функциям связываться с неконстантными ссылками в версиях до VC ++ 2005. Это поведение было исправлено в VC ++ 2005 и выше .

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

CSingleLock(&m_criticalSection, TRUE).Lock();  // Yikes!

MS COMPILER NOTE : Версии MSVC ++ до Visual Studio .NET 2003 некорректно разрешали функциям связываться с неконстантными ссылками в версиях до VC ++ 2005. Это поведение было исправлено в VC ++ 2005 и выше .

5
ответ дан 28 November 2019 в 17:16
поделиться

Нет, нет способа сделать это. Это приведет к поломке почти всего кода C ++, который в значительной степени зависит от создания безымянных временных файлов. Единственное решение для определенных классов - сделать их конструкторы закрытыми, а затем всегда создавать их с помощью какой-то фабрики. Но я думаю, что лекарство хуже болезни!

3
ответ дан 28 November 2019 в 17:16
поделиться

Я так не думаю.

Хотя это неразумно - как вы выяснили с помощью своей ошибки - в заявлении нет ничего "незаконного". Компилятор не имеет возможности узнать, является ли возвращаемое из метода значение «жизненно важным».

2
ответ дан 28 November 2019 в 17:16
поделиться
Другие вопросы по тегам:

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