When writing a program, I aim to avoid any unspecified or implementation-defined behaviour. When linking to C++ libraries, I expect them to have been written in a similar way. If I link to a library that used implementation-defined behaviour when it was compiled, does that instantly make my own program implementation-defined according to the standard?
Does it even matter at this point? If the library has already been compiled to object code, I’m not even dealing with implementation-defined C++ – in fact, it may not have even been written in C++. How about when I use an API that is by its nature platform dependent, such as POSIX?
The way that the standard is written seems to assume my “C++ program” is entirely written by me and involves no other pre-compiled components. How does it accommodate the linking of these components and at what points does the standard stop caring about what my program does?
If you call a function that has unspecified (or implementation-defined, or undefined) behavior, then your program has unspecified (or implementation-defined, or undefined) behavior.
The standard does not define what it means for a program “to be implementation-defined”, so I can’t answer that part other than to say no, your program is not implementation-defined according to the standard. Its behavior is.
If you use call a function from Posix, then your program depends on (that part of) Posix. The behavior of such a program isn’t defined by the C++ standard alone, because the C++ standard doesn’t know or care what the Posix function does. However, given knowledge of what the Posix function does, you can use the C++ standard to work out what the whole program does. So behavior can be defined by the C++ standard, except for the part that’s outside the scope of the C++ standard.
There are also certain situations where you can make your program have undefined behavior simply by linking to a library, without calling the code in it. Violating the One Definition Rule is the obvious example. So far as the standard is concerned, you’re entitled to define a function called
pthread_create, but if you link that program against pthreads, you have undefined behavior.There is something of a grey area, whether Posix and other OS functions are “part of the program” or “part of the implementation”. Take for example
strdup, which you could easily implement for yourself in a non-Posix environment. If it’s “part of the implementation” then of course its behavior is implementation-defined. If it’s “part of the program” then the behavior of the program is, well, dependent on the program, in common with the behavior of every C++ program! The C++ standard doesn’t really care which way you choose to think of it.The standard doesn’t assume anything about how many authors a program has. Provided that the components you use are documented, it’s your responsibility as the person who puts the final program together, to work out whether or not you have used them in a way that makes your program’s behavior as defined as you’d like it to be. If they’re not documented, or they don’t behave as their documentation says they should, then you might like to present a case to their authors that they have a responsibility to do something about that 😉