Статическая глобальная переменная, используемая встроенной функцией-членом - PullRequest
10 голосов
/ 07 марта 2011

Если в заголовочном файле C ++ имеется статическая глобальная переменная, каждая единица перевода, которая включает файл заголовка, заканчивается собственной копией переменной.

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

#include <iostream>

static int n = 10;

class Foo {
 public:
   void print() { std::cout << n << std::endl; }
};

тогда я вижу немного странное поведение в gcc 4.4:

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

  2. Если я компилирую с -O2, при каждом использовании функции-члена используется копия переменной из единицы перевода, в которой сделан регистр.

Очевидно, что это действительно плохой дизайн, поэтому этот вопрос просто из любопытства. Но мой вопрос, тем не менее, что стандарт C ++ говорит об этом случае? Правильно ли работает g ++, давая другое поведение с включенной оптимизацией и без нее?

1 Ответ

12 голосов
/ 07 марта 2011

Стандарт гласит (3.2 / 5):

Может быть более одного определения типа класса (пункт 9), ... при условии, что определения удовлетворяют следующим требованиям ...в каждом определении D соответствующие имена, которые рассматриваются в соответствии с 3.4, должны относиться к объекту, определенному в определении D, или должны относиться к одному и тому же объекту

. Здесь ваш код проигрывает.Использование n в различных определениях Foo не относится к одному и тому же объекту.Игра окончена, неопределенное поведение, так что да, gcc имеет право делать разные вещи на разных уровнях оптимизации.

3.2 / 5 продолжается:

за исключением того, что имя может ссылаться на const-объектс внутренней связью или без нее, если объект имеет один и тот же интеграл или тип перечисления во всех определениях D, и объект инициализируется с помощью константного выражения (5.19), и используется значение (но не адрес) объекта, иобъект имеет одинаковое значение во всех определениях D

Так что в вашем примере кода вы можете превратить n в static const int, и все будет прекрасно.Не случайно в этом разделе описываются условия, при которых не имеет значения, ссылаются ли разные TU на один и тот же объект или разные объекты - все, что они используют - это постоянное значение времени компиляции, и все они используют один и тот же.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...