Подтвердить что ты не робот

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

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

Lock();

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

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

Имеются ли какие-либо правильные примеры этого утверждения? Есть ли какие-то известные и популярные идиомы, которые включают такие заявления? Зачем мне такие утверждения в правильной программе?

4b9b3361

Ответ 1

Он не выглядит более странным, чем вызов функции void с именем 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. Но если класс - это то, что вы уже используете, это самая простая вещь, которая работает.

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

Ответ 2

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

например. is_base_of

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

Ответ 3

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

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

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

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

Ответ 4

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

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

Я столкнулся с такой проблемой недавно. Мне нужна была функция, которая бы рекурсивно вызывала себя, но я хотел, чтобы рекурсия была разрешена во время компиляции. В моем случае, однако, я использовал статическую функцию внутри такого класса, потому что часто мне нужно вернуть что-то другое, чем 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 этого типа.

Ответ 5

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