Какова цель анонимных {} блоков в языках стиля C (C, С++, С#)
Пример -
void function()
{
{
int i = 0;
i = i + 1;
}
{
int k = 0;
k = k + 1;
}
}
Изменить - Спасибо за отличные ответы!
Какова цель анонимных {} блоков в языках стиля C (C, С++, С#)
Пример -
void function()
{
{
int i = 0;
i = i + 1;
}
{
int k = 0;
k = k + 1;
}
}
Изменить - Спасибо за отличные ответы!
Он ограничивает область видимости в блоке внутри {}.
Кронштейны обозначают область видимости - все, что объявлено в скобках, невидимо вне их.
Кроме того, в С++ объект, выделенный в стеке (например, без использования "нового" ), будет разрушен, когда он выходит из области видимости.
В некоторых случаях это может быть также способ выделить конкретный элемент функции, который, по мнению автора, заслуживает внимания для людей, которые смотрят на источник. Является ли это хорошим использованием или нет, является спорным, но я видел это.
Они часто полезны для RAII, что означает, что данный ресурс будет выпущен, когда объект выходит за рамки. Например:
void function()
{
{
std::ofstream out( "file.txt" );
out << "some data\n";
}
// You can be sure that "out" is closed here
}
Другим распространенным применением функций OpenGL glPushMatrix()
и glPopMatrix()
является создание логических блоков, относящихся к стеку матрицы:
glPushMatrix();
{
glTranslate(...);
glPushMatrix();
{
glRotate(...);
// draw some stuff
}
glPopMatrix();
// maybe draw some more stuff
}
glPopMatrix();
{ ... }
открывает новую область
В С++ вы можете использовать их следующим образом:
void function() {
// ...
{
// lock some mutex.
mutex_locker lock(m_mutex);
// ...
}
// ...
}
После того, как управление выходит из блока, блокировка мьютекса уничтожается. И в своем деструкторе он автоматически разблокирует мьютекс, к которому он подключился. Это очень часто делается и называется RAII (сбор ресурсов - это инициализация), а также SBRM (управление ресурсами с привязкой к областям). Другим распространенным приложением является выделение памяти, а затем в деструкторе освободить эту память еще раз.
Другая цель - сделать несколько подобных вещей:
void function() {
// set up timer A
{
int config = get_config(TIMER_A);
// ...
}
// set up timer B
{
int config = get_config(TIMER_B);
// ...
}
}
Это будет держать вещи раздельными, поэтому можно легко найти различные строительные блоки. Вы можете использовать переменные с тем же именем, как это делает код выше, потому что они не видны за пределами их области действия, поэтому они не конфликтуют друг с другом.
class ExpensiveObject {
public:
ExpensiveObject() {
// acquire a resource
}
~ExpensiveObject() {
// release the resource
}
}
int main() {
// some initial processing
{
ExpensiveObject obj;
// do some expensive stuff with the obj
} // don't worry, the variable scope ended, so the destructor was called, and the resources were released
// some final processing
}
Создавая новую область, они могут использоваться для определения локальных переменных в инструкции switch.
например.
switch (i)
{
case 0 :
int j = 0; // error!
break;
против.
switch (i)
{
case 0 :
{
int j = 0; // ok!
}
break;
Они очень часто используются для переменных диапазона, поэтому переменные локальны для произвольного блока, определенного фигурными скобками. В вашем примере переменные я и k недоступны вне их охватывающих фигурных скобок, поэтому они не могут быть изменены каким-либо подлым способом и что эти имена переменных могут быть повторно использованы в другом месте вашего кода. Еще одно преимущество использования фигурных скобок для создания локальной области видимости заключается в том, что на языках с сборкой мусора сборщик мусора знает, что он безопасен для очистки переменных вне области видимости. Это не доступно в C/С++, но я считаю, что он должен быть в С#.
Один простой способ подумать о том, что фигурные скобки определяют атомную часть кода, вроде пространства имен, функции или метода, но без фактического создания пространства имен, функции или метода.
Вы делаете две вещи.
Насколько я понимаю, они просто для обзора. Они позволяют повторно использовать имена переменных в родительских/дочерних областях, которые могут быть полезны время от времени.
EDIT: на этот вопрос был дан ответ на еще один вопрос. Надеюсь, что это поможет.
Как упоминалось в предыдущих плакатах, это ограничивает использование переменной в области, в которой она объявлена.
В сборках мусора, таких как С# и Java, он также позволяет сборщику мусора возвращать память, используемую любыми переменными, используемыми в пределах области действия (хотя установка переменных в null будет иметь тот же эффект).
{
int[] myArray = new int[1000];
... // Do some work
}
// The garbage collector can now reclaim the memory used by myArray
Конечно, конечно. (Неужели эта лошадь была избита до смерти?)
Но если вы посмотрите на определение языка, вы увидите такие шаблоны, как:
Это упрощает синтаксис языка, что составной оператор является всего лишь одним из нескольких возможных выражений.
составной оператор: { statement-list opt}
оператор-список:
утверждение:
Что касается области видимости, она относится к видимости переменных и методов в одной части программы для другой части этой программы, рассмотрим этот пример:
int a=25;
int b=30;
{ //at this point, a=25, b=30
a*=2; //a=50, b=30
b /= 2; //a=50,b=15
int a = b*b; //a=225,b=15 <--- this new a it's
// declared on the inner scope
}
//a = 50, b = 15
Если вы ограничены ANSI C, они могут использоваться для объявления переменных ближе к тому, где вы их используете:
int main() {
/* Blah blah blah. */
{
int i;
for (i = 0; i < 10; ++i) {
}
}
}
Не обязательно для современного компилятора C.
Я использую его для блоков кода, которым нужны временные переменные.
Полезное использование-cas ihmo определяет критические разделы в С++. например:.
int MyClass::foo()
{
// stuff uncritical for multithreading
...
{
someKindOfScopeLock lock(&mutexForThisCriticalResource);
// stuff critical for multithreading!
}
// stuff uncritical for multithreading
...
}
с помощью анонимной области не требуется явно вызывать блокировку/разблокировку мьютекса или семафора.