я не использую VS2008 для C++, только VB & C#, но я нахожу, что, когда intellisense прекращает работать (верный для VS2003/2005/2008) это - потому что что-то в проекте/файле повреждается - обычно неверная ссылка или код.
VB и C# имеют намного лучше intellisense, поддерживают из-за способности размышлять над блоками, на которые ссылаются, для создания intellisense дерева.
C++ должен обойти включать файлы для прототипов функции, и если пути не будут корректны, то он не найдет все заголовки прототипа.
Я считаю, что этот код приводит к двойному разыменованию при доступе к элементам вектора
Не обязательно. Компиляторы довольно умны и должны уметь исключать общие подвыражения. Они могут видеть, что оператор []
не изменяет «указатель на первый элемент», поэтому им не нужно заставлять ЦП перезагружать его из памяти при каждой итерации цикла.
Что не так с вашей идеей, так это то, что у вас уже есть два совершенно хороших решения:
Конечно, вы можете утверждать, что пара итераторов имеет «менее естественный синтаксис», но я не согласен. Это совершенно естественно для любого, кто привык к STL. Это эффективно и дает вам именно то, что вам нужно для работы с диапазоном, используя стандартные алгоритмы или ваши собственные функции.
Пары итераторов - это обычная идиома C ++, и программист на C ++, читающий ваш код, поймет их без проблем, в то время как они будут удивлены вашими домашними обертками для векторных изображений.
Если вы » re действительно параноик по поводу производительности, передайте пару итераторов. Если синтаксис вас действительно беспокоит, передайте вектор и доверяйте компилятору.
В чем недостаток этой идеи?
Просто: это преждевременная оптимизация. Альтернативы: принять vector
и использовать итераторы или передать итераторы непосредственно в функцию.
Передача по значению, если вы не уверены, что передача по ссылке улучшает производительность.
При передаче по значению может произойти исключение копирования, что приведет к аналогичной, если не лучшей производительности.
Дэйв написал об этом здесь:
http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
Вы правы, здесь есть лишнее косвенное обращение. Возможно (хотя это было бы удивительно), если бы компилятор (с помощью генерации кода во время компоновки) оптимизировал его.
То, что вы предложили, иногда называется нарезкой, и в некоторых ситуациях это широко используется. Хотя в целом я не уверен, что это стоит опасностей. Вы должны быть очень осторожны, не допуская аннулирования вашего среза (или чужого).
Обратите внимание, что если вы использовали итераторы для цикла вместо индексации, вы бы разыграли ссылку только пару раз (чтобы вызвать begin ()
и end ()
), а не n раз (для индексации в вектор).
int sum(const vector<int> &v)
{
int s = 0;
for (auto it = v.begin(); it != v.end(); ++it) {
s += fn(*it);
}
return s;
}
(Я предполагаю, что оптимизатор поднимет end ()
вызовы из цикла. Вы можете сделать это явно, чтобы быть уверенным. )
Передача пары итераторов вместо самого контейнера кажется идиомой STL. Это дало бы вам больше общего, так как тип контейнера может меняться, но может меняться и количество необходимых разыменований.
Двойного разыменования не существует, потому что компилятор, вероятно, передаст реальный указатель на вектор в качестве аргумента, а не указатель на указатель. Вы можете просто попробовать это и проверить представление дизассемблера вашей IDE, чтобы узнать, что на самом деле происходит за кулисами:
void Method(std::vector<int> const& vec) {
int i = vec.back();
}
void SomeOtherMethod() {
std::vector<int> vec;
vec.push_back(1);
Method(vec);
}
Что здесь происходит? Вектор размещается в стеке. Первый возврат транслируется в:
push eax // this is the constant one that has been stored in eax
lea ecx,[ebp-24h] // ecx is the pointer to vec on the stack
call std::vector<int,std::allocator<int> >::push_back
Теперь мы вызываем Method (), передавая вектор const &:
lea ecx,[ebp-24h]
push ecx
call Method (8274DC0h)
Неудивительно, что указатель на вектор передается, поскольку ссылки являются не чем иным, как постоянно разыменованными указателями. Теперь внутри метода () снова осуществляется доступ к вектору:
mov ecx,dword ptr [ebp+8]
call std::vector<int,std::allocator<int> >::back (8276100h)
Указатель вектора берется непосредственно из стека и записывается в ecx.