0

Before I begin I want to say I'm using Visual Studio 2013 Express Update 4 and compiling with optimization on (/O2 and /Ot).

I was making a test with vector iterators like this:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<char*> List = {"String 1", "String 2", "This is string 3"};

    for (auto it = List.begin(); it != List.end(); it++)
        cout << *it << endl;

    return 0;
}

and then looked at the disassembly and saw some ridiculously big Assembly code (about 200 lines only for the for loop and cout)

Then I tried like this:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<char*> List = {"String 1", "String 2", "This is string 3"};

    for (auto i = 0U; i < List.size(); i++)
        cout << List[i] << endl;

    return 0;
}

Then the dissablembled code got very much smaller (about 55 lines).

So my question is: is it supposed to be like that or it may be a compiler bug? What is the most correct and the fastest way to access a vector's content?

LHLaurini
  • 1,737
  • 17
  • 31
  • 1
    Did you compare running time and executable size? What do you mean by "optimization on"? – Guvante Mar 27 '15 at 21:37
  • VS tends to include a bunch of diagnostics ("safe mode") that need to be turned off explicitly, even in their "Release" mode. – Ulrich Eckhardt Mar 27 '15 at 21:37
  • 1
    VisualStudio allows you to perform [iterator checks](https://msdn.microsoft.com/en-us/library/hh697468.aspx?f=255&MSPPError=-2147217396) even in Release mode (I assume that is what you mean by *optimization on*). Make sure such checks are disabled (which is the default setting, unless you muck with it). – Praetorian Mar 27 '15 at 21:40
  • 1
    Why do you care how many lines the disassembled code is? – David Schwartz Mar 27 '15 at 21:40
  • Compare it with `for (char * s : List) { cout << s << endl; }`. – Kerrek SB Mar 27 '15 at 21:42
  • @Praetorian Thanks, that's it. I put a `#define _ITERATOR_DEBUG_LEVEL 0` line and it compiled to ~45 lines. That was the problem. You should post it as a answer. – LHLaurini Mar 27 '15 at 21:47
  • 1
    And replace `it++` with `++it`, might shave instruction or two – Severin Pappadeux Mar 27 '15 at 21:49
  • 3
    @LHLaurini Go ahead and post an answer with what you found out. You should also try and figure out why the iterator debug isn't zero for a release build to begin with. – Praetorian Mar 27 '15 at 21:51
  • Please note that explicitely lowering `_ITERATOR_DEBUG_LEVEL` is almost always the wrong thing to do. Debug style builds default to it on and Release style builds default to it off. My guess is that you're trying to make a Debug style build fast by adding some optimisation flags but not all (at a guess you're using /MTd instead of /MT or /MDd instead of /MD) – Mike Vine Mar 27 '15 at 22:07
  • @Praetorian Because I was not using a release build (sorry forgot to say that *embarrased*), so this is something that wouldn't bother. – LHLaurini Mar 28 '15 at 00:33

1 Answers1

3

It's a matter of compiler quality of implementation versus optimisation setting.

Your comment about compiling with "optimisation on" doesn't say much. Although some optimisation settings are concerned with reducing code size, it is quite common for optimisation to be concerned with other measures, such as runtime speed or even memory usage. Optimisation for runtime speed, for example, often trades off code size (e.g. amount of assembler) to achieve performance - there is no hard and fast rule requiring that, if two bits of code achieve identical output, the faster one is smaller.

The primary definition of a bug in a compiler is correctness of the result when code is compiled/linked/executed (i.e. that it produces results within constraints defined by the C++ standard). If you are using an optimisation setting concerned with minimising output code size, then the concern is one of compiler quality not of correctness.

There is no hard and fast rule about what method should be used to access elements of a vector - there are use cases. All methods are correct, if they achieve the required effect unambiguously (e.g. without exhibiting undefined behaviour). Although there are constraints on behaviour some operations (e.g. accessing an element by index is a constant time operation) most useful programs use a number of operations, and the interactions vary between implementations of the library. So if such things are really important, you need to test and pick the one that meets your requirements.

If you are using an optimisation setting that specifically is concerned with minimising code size, you may have a reportable bug. The amount that will matter to the vendor (Microsoft in your case) comes down to how important they consider that type of optimisation is to their paying customer base.

In practice, I would very rarely worry about size of emitted code from a compiler, unless storage space is at a premium. Get the code running reliably and correctly first, and then worry about whether the executable size can be reduced. An executable that is small but doesn't work as required is not particularly useful.

Peter
  • 35,646
  • 4
  • 32
  • 74
  • My concern wasn't about space. It was about speed. I know that a smaller code isn't necessarily faster (but when it is 4x smaller, it's a little obvious). I just looked in the code size before I did a speed test. Well, I won't even need to. Thanks for your answer. PS: The optimization was set to /O2 (maximize speed). – LHLaurini Mar 28 '15 at 00:44