"Std:: size_t" имеет смысл в С++?

В некотором коде, который я унаследовал, я часто использую size_t с квалификатором пространства имен std. Например:

std::size_t n = sizeof( long );

Он компилируется и работает нормально, конечно. Но мне кажется плохой практикой (возможно, перенесенной с C?).

Не правда ли, что size_t встроен в С++ и, следовательно, в глобальное пространство имен? Должен ли заголовочный файл использовать size_t в С++?

Другой способ задать этот вопрос: не ожидается ли компиляция следующей программы (без включения) для всех компиляторов С++?

size_t foo()
{
    return sizeof( long );
}

Ответы

Ответ 1

Кажется, у толпы stackoverflow есть путаница относительно этого

::size_t определяется в заголовке обратной совместимости stddef.h. Он был частью ANSI/ISO C и ISO C++ с самого начала. Каждая реализация С++ должна поставляться с stddef.h (совместимостью) и cstddef, где только последняя определяет std::size_t и необязательно ::size_t. См. Приложение D стандарта С++.

Ответ 2

В разделе 17.4.1.2 стандарта С++, параграф 4, указано, что:

"Однако в стандартной библиотеке С++ декларации и определения (за исключением имен, которые определены как макросы в C) находятся в области пространства имен (3.3.5) пространства имен std."

Это включает элементы, найденные в заголовках шаблона cname, включая cstddef, который определяет size_t.

Итак, std:: size_t на самом деле прав.

Ответ 3

Вы можете получить size_t в глобальном пространстве имен, включив, например, <stddef.h> вместо <cstddef>. Я не вижу никакой очевидной выгоды, и функция устарела.

Ответ 4

size_t не встроен в С++. И он не определяется по умолчанию. Это не компилируется с помощью GCC:

int main(int argc, char** argv) {
size_t size;
}

Тем не менее, size_t является частью POSIX, и если вы используете только такие основные вещи, как <cstdlib>, вы, скорее всего, закончите тем, что он определен.

Можно утверждать, что std:: size_t является эквивалентом С++ для size_t. Как отметил Брайан, std:: используется как пространство имен, чтобы избежать установки глобальных переменных, которые не подходят всем. Это просто как std::string, который также может быть определен в корневом пространстве имен.

Ответ 5

std::size_t n = sizeof( long );

Собственно, вы не спросили, что конкретно кажется плохой практикой в ​​вышеупомянутом. Использование size_t, квалификация с пространством имен std,...

Как утверждает стандарт С++ (18.1), size_t - это тип, определенный в стандартном заголовке. Я предлагаю отказаться от любых мыслей и впечатлений о возможном наследовании с языка C. С++ - это отдельный и другой язык, и лучше рассмотреть его как таковой. Он имеет собственную стандартную библиотеку, и все элементы стандартной библиотеки С++ определены в пространстве имен std. Однако в С++ можно использовать элементы C Standard Library.

Я бы подумал о включении в качестве грязного взлома. В стандарте С++ указано, что содержимое заголовков одинаковое или основано на соответствующих заголовках из стандартной библиотеки C, но в ряде случаев были применены изменения. Другими словами, это не прямая копия и вставка заголовков C в заголовки С++.

size_t не является встроенным типом в С++. Это тип, определенный для указания того, какой тип интеграла используется как возвращаемый тип оператора sizeof(), поскольку фактический тип возвращаемого значения sizeof() определяется реализацией, поэтому стандарт С++ унифицируется путем определения size_t.

будет следующая программа (без включает в себя) все компиляторы С++?

size_t foo()
{
    return sizeof( long );
}

В стандарте С++ говорится (1.4):

Имена, определенные в библиотеке, имеют область пространства имен (7.3). Модуль перевода С++ (2.1) получает доступ к этим именам, включая соответствующий стандартный заголовок библиотеки (16.2).

size_t - это имя, определенное в пространстве имен std, поэтому каждая программа, использующая это имя, должна включать соответствующий заголовок в этом случае.

Далее в главе 3.7.3 говорится:

Однако, ссылаясь на std, std:: bad_alloc и std:: size_t, плохо сформирован, если имя не было объявлено включением соответствующего заголовка.

Учитывая, что программа с использованием size_t, но не включая заголовок, плохо сформирована.

Ответ 6

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

size_t является стандартным типом С++ и определяется в пространстве имен std.

Ответ 7

Я думаю, что разъяснения достаточно ясны. std::size_t имеет смысл в С++ и ::size_t сделать (по крайней мере) здравый смысл в C.

Однако вопрос остается. А именно, можно ли считать, что ::size_t и std::size_t совместимы?

С точки зрения чистого вида они не обязательно идентичны, если они не определены где-то, что они должны быть идентичными.

Я думаю, что многие используют что-то a la:

----
// a.hpp 
#include <string>

void Foo( const std::string & name, size_t value );

-----
// a.cpp
#include "a.hpp"

using namespace std;

void Foo( const string & name, size_t value ) 
{
  ...
}

Итак, в заголовке вы defintely используете ::size_t, а в исходном файле вы будете использовать std::size_t. Значит, они должны быть совместимыми, верно? В противном случае вы получите ошибку компилятора.

/Майкл С.

Ответ 8

Заголовки компилятора GNU содержат что-то вроде

typedef long int __PTRDIFF_TYPE__;
typedef unsigned long int __SIZE_TYPE__;

Затем stddef.h вызывает нечто вроде

typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __SIZE_TYPE__ size_t;

И, наконец, файл cstddef содержит что-то вроде

#include <stddef.h>

namespace std {

  using ::ptrdiff_t;
  using ::size_t;

}

Я думаю, что это должно быть ясно. Пока вы включаете <cstddef> вы можете использовать либо size_t, либо std:: size_t, потому что size_t был зашифрован вне пространства имен std и затем был включен. Эффективно у вас есть

typedef long int ptrdiff_t;
typedef unsigned long int size_t;

namespace std {

  using ::ptrdiff_t;
  using ::size_t;

}