Есть ли веские аргументы в пользу создания временного файла, который немедленно уничтожается и не используется напрямую в C ++? - PullRequest
16 голосов
/ 29 июня 2011

Вдохновлен этим вопросом . Предположим, у меня есть class Lock с конструктором по умолчанию, и в некотором коде я пишу следующее утверждение:

Lock();

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

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

Существуют ли допустимые варианты использования вышеприведенного утверждения? Существуют ли известные и популярные идиомы, которые включают такие заявления? Зачем мне такие заявления в правильной программе?

Ответы [ 5 ]

14 голосов
/ 29 июня 2011

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

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

Пока не могу придумать вескую причину для создания, но не использовать Lock, но:

LockSession(lock);

имеет те же побочные эффекты, которые вы ожидаете от:

acquire_and_then_immediately_release(lock);

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

{
    LockSession session(lock);
    // release immediately
}

или, если на то пошло:

void acquire_and_then_immediately_release(Lock &lock) {
    LockSession(lock);
}

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

Почему вы хотите приобрести, а затем немедленно снять блокировку? Возможно, потому что вы (ab) используете его как слегка своеобразный семафор. Например, вы могли бы создать группу потоков с удерживаемой блокировкой, и если первое, что делает каждый поток, это, то ни один из них не пройдет мимо него, пока не будет выполнено все создание потока (плюс все остальное, что родитель хочет, чтобы потоки быть в состоянии видеть), и родитель снимает блокировку. Вероятно, есть лучшие примеры объектов, побочные эффекты которых значительны.

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

xml::dom::Document(mystring);

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

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

1 голос
/ 30 марта 2013

Чтобы уйти от опасной вариадики в стиле va_list, я написал код, который вы называете так:

MyFunc() << a << b << c;

Где MyFunc реализован как класс с operator <<и ~MyFunc() отвечает за выполнение желаемой работы.Неловко писать класс MyFunc, но как только это будет сделано, все будет работать хорошо.

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

1 голос
/ 29 июня 2011

Аналогичный синтаксис создания временного файла часто используется в метапрограммах template или boost. Они на самом деле не создают временные, но имитируют его эффект .

например. is_base_of

Вы можете увидеть синтаксис временных объектов в трюке sizeof().

0 голосов
/ 29 июня 2011

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

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

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

Рассмотрим следующий пример:

#include <stdio.h>

template <typename T, int i>
struct megapower {
  megapower(T &val) {
    val*=val;
    {megapower<T,i-1> tmp(val);}
  }
};

template <typename T>
struct megapower<T,1> {
  megapower(T &val) {}
};

int main() {
  int v=2;
  {megapower<int,5> tmp(v);}
  printf("%d\n",v);
  return 0;
}

Будет вычислено 2 ^ 2 ^ 2 ^ 2 ^ 2 = 65536.

P.S. Оказывается, вы не можете написать megapower<int,5>(v). Компилятор подумает, что вы пытаетесь создать новый объект v этого типа.

0 голосов
/ 29 июня 2011

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

...