Search code examples
c++visual-c++c-preprocessorprecompiled-headers

How to override preprocessor definition for a single unit when using precompiled headers?


Initial problem:
I have a bug caused by an old debug MSVCRT library.
It throws an exception in debug mode for std::string initialization:

std::string str{vecBuff.cbegin(), vecBuff.cend()};

The old debug runtime library detects that std::vector<char>::cend() points to an invalid address and causes an error about HEAP Courruption. It only happens within a MSI Custom Action invocation (and there's an old runtime version which I can do nothing about).

In the comments to this answer there is a solution to set _ITERATOR_DEBUG_LEVEL 1.
I don't want to do that for the whole library. Unfortunatelly, I can't manage to do it for the single .cpp either.
This .cpp uses a precompiled header and disabling it for a single file in the properties changes nothing. I still get an error about stdafx.h missing.

// stdafx.h
#pragma once

#include <string>
// the .cpp file

// Can't include before. Get a lot of warnings.
#include "stdafx.h"

// will not have any effect since <string> is already included in "stdafx.h"
#if _MSC_VER && \
    !__INTEL_COMPILER && \
    _DEBUG
#define _ITERATOR_DEBUG_LEVEL 1
#endif
#include <string>

Though I am initially trying to solve the std::string initialization problem, I'd like to know the answer to a more generic topic, since there are some other places where I might require to customize preprocessof definitions AND use a precompiled header.


Solution

  • Defining _ITERATOR_DEBUG_LEVEL to either 1 or 2 changes the representation of iterators. Instead of being lightweight wrappers for e.g. plain pointers into container data, iterators compiled with this option contain a pointer into the data and a pointer to a container proxy object, which contains more info about the container. Thus a program where some object are compiled with _ITERATOR_DEBUG_LEVEL set to 0 and others with _ITERATOR_DEBUG_LEVEL set to something else contains two incompatible versions of each iterator type. This is not a good idea. The compiler therefore tries to detect a mix of different debug levels and introduce a deliberate linker error if a mismatch is found. Even if you manage to inhibit this check somehow, passing iterators between functions compiled with different _ITERATOR_DEBUG_LEVEL value is usually fatal.