Я прочитал (внутри объектной модели C ++), что адрес указателя на элемент данных в C ++ является смещением элемента данных плюс 1?
Я пытаюсь это на VC ++ 2005, но я не получаю точные значения смещения.
Например:
Class X{
public:
int a;
int b;
int c;
}
void x(){
printf("Offsets of a=%d, b=%d, c=%d",&X::a,&X::b,&X::c);
}
должен печатать смещения a = 1, b = 5, c = 9. Но в VC ++ 2005 это будет a = 0, b = 4, c = 8.
Я не могу понять это поведение.
Отрывок из книги:
«Это ожидание, однако, опровергается одним - несколько традиционная ошибка для программистов как на C, так и на C ++.
Физическое смещение трех координатных членов в классе расположение соответственно 0, 4 и 8, если vptr размещен в конец или 4, 8 и 12, если vptr находится в начале учебный класс. Значение, возвращаемое от взятия адреса участника, однако, всегда увеличивается на 1. Таким образом, фактические значения 1, 5 и 9, и скоро. Проблема заключается в различении указателя на отсутствие данных член и указатель на первый член данных. Рассмотрим для примера:
float Point3d :: * p1 = 0; float Point3d :: * p2 = & Point3d :: x; // упс: как отличить? if (p1 == p2) { cout << "p1 & p2 содержат одинаковое значение -"; cout << "они должны обратиться к одному и тому же участнику!" << endl; }
Чтобы различать p1 и p2, каждое фактическое значение смещения элемента увеличено на 1. Следовательно, и компилятор (и пользователь) должны помнить Есть ли версия в духе C ++?
Я постоянно вспоминаю о том, что, когда вы разрешаете сложные типы, возникает риск возникновения исключений в конструкторе типа. И, поскольку язык в настоящее время разработан, нет абсолютно никакого способа отловить такое исключение. Если бы было решено, что такие исключения следует перехватывать, тогда это потребовало бы значительно большей работы как для комитета, так и для авторов компилятора, что сделало бы все это несколько более проблематичным, чем просто сказать «разрешить std :: vector
".
Могут быть и другие проблемы. Вся «несовместимость со средой выполнения» кажется мне отвлекающим маневром, учитывая, что теперь вы можете обеспечить практически ту же функциональность с помощью макросов. Но что-то вроде этого гораздо сложнее.
Как и @jalf, я иногда ловлю себя на том, что пишу
int main(int argc, char** argv) {
std::vector<std::string> args(argv, argv+argc);
Но да, как все сказали, main
должен быть C-совместимым. Я рассматриваю его как интерфейс для среды выполнения ОС, которая (по крайней мере, в тех системах, которые я использую) написана на C.
Хотя некоторые среды разработки поощряют замены, такие как wmain
или _tmain
. Вы можете написать свой собственный компилятор / IDE, который будет поощрять использование int vmain (const std :: vector
.
В основном, чтобы оставаться совместимыми с C. Если бы мы отказались от этого, main () переместилась бы в класс.
Есть еще одна причина, кроме совместимости с C. В C++, стандартная библиотека должна быть полностью необязательной. В самом языке C++ нет ничего, что заставляло бы вас использовать такие вещи из стандартной библиотеки, как std::string
и std::vector
, и это совершенно случайно. На самом деле, по замыслу, вы должны иметь возможность использовать некоторые части стандартной библиотеки без необходимости использовать другие (хотя это и привело к таким раздражающим вещам, как std::ifstream
и std::ofstream
, работающие со строками const char*
в стиле C, а не с объектами std::string
).
Теория заключается в том, что вы должны иметь возможность взять язык C++ и использовать любую библиотеку объектов, контейнеров и т.д., которую вы хотите, будь то стандартная библиотека или какая-то собственная библиотека (например, Qt, MFC), или что-то, что вы создали сами. Определение main
для приема аргумента, состоящего из типов, определенных в стандартной библиотеке, противоречит этой цели проектирования.
Потому что это заставит вас включить <вектор>
и <строка>
.
Я попытаюсь объяснить в лучшем из возможных предложений.
C++ был разработан для обратной совместимости с C, и std::vector
был включен в библиотеку, которая появилась только в C++.
Кроме того, программы на C++ и C были разработаны для запуска в оболочках или командных строках (windows, linux, mac), а ОС передают аргументы программе в виде массива String. Как бы ОС действительно переводила векторы?
Это самая большая причина, которую я могу придумать, не стесняйтесь критиковать ее.
Потому что C++ существовал задолго до появления стандарта C++ и в значительной степени основывался на C. И, как и в оригинальном стандарте ANSI C, кодификация существующей практики была его важной частью.
Нет смысла менять то, что работает, особенно если это приведет к поломке целого ряда существующих кодов.
Даже ISO C, который прошел через множество итераций, все еще относится к обратной совместимости очень серьезно.
Множественные определения main () на самом деле не являются множественными определениями. Их три:
int main (void)
(C99) int main (int argc, char * argv [])
(C99) int main (int argc, char * argv [], char * envp [])
(POSIX, я думаю) Но в POSIX вы только действительно получаете третий. Тот факт, что вы можете вызывать функцию с дополнительными аргументами, зависит от соглашения о вызовах C.
Вы не можете иметь extern "C" int main (std :: vector
, если только макет памяти не окажется магически совместимым в портативный способ. Среда выполнения вызовет main () с неправильными аргументами и завершится ошибкой. Нет простого способа обойти это.
Вместо этого, при условии, что main () не extern «C»
, среда выполнения может пробовать различные поддерживаемые символы по порядку, пока не найдет один. Я полагаю, что main () - это extern «C»
по умолчанию, и что вы не можете перегружать функции extern «C»
.
Для большего удовольствия void main (void) .
Потому что C++ был разработан для (почти) обратной совместимости с кодом на C.
Есть случаи, когда код на Си будет ломаться в компиляторе Си++, но они довольно редки, и обычно есть веская причина, почему эта поломка необходима.
Но изменение сигнатуры main, хотя и удобно для нас, не является необходимым. Для кого-то, портирующего код с C, это будет просто еще одна вещь, которую придется изменить, без особого выигрыша.
Другая причина в том, что std::vector
- это библиотека, а не часть основного языка. И поэтому вам придется #include
в каждой программе на C++.
И конечно, в первые годы своего существования C++ не имел вектора. Поэтому, когда вектор был добавлен в язык, конечно, они могли изменить сигнатуру main
, но тогда они сломали бы не только код на C, но и каждую существующую программу на C++.
Стоит ли оно того?