Case 32 — Parameter Default Value Changes (C++)¶
| Field | Value |
|---|---|
| Verdict | ✅ NO_CHANGE |
| Category | No Change |
| Platforms | Linux, macOS, Windows |
| Flags | — |
Detected ChangeKinds |
— |
| Source files | browse on GitHub |
Category: C++ Defaults | Verdict: 🟢 NO_CHANGE (binary ABI unchanged)
What changes¶
| Method | v1 signature | v2 signature | Effect |
|---|---|---|---|
connect |
void connect(int timeout = 30) |
void connect(int timeout = 60) |
Default changed |
configure |
void configure(bool verbose = true, int retries = 3) |
void configure(bool verbose, int retries = 5) |
verbose lost default; retries changed |
disconnect |
void disconnect(int code) |
void disconnect(int code = 0) |
Default added |
Why this is NOT a binary ABI break¶
In C++, default parameter values are resolved at the call site during compilation.
When the compiler sees conn.connect(), it rewrites it to conn.connect(30) using
the default from the header at compile time. The library's .so never knows about
default values — it only receives the actual arguments.
This means:
-
Default changed (timeout 30 -> 60): Binaries compiled against v1 will always pass
30. Only code recompiled against v2 will pass60. No binary break. -
Default removed (verbose): Binaries compiled against v1 already have
truebaked in. Only recompilation against v2 would fail (source break) becauseconfigure()with zero args is no longer valid. -
Default added (disconnect): Existing binaries already pass explicit values. New code compiled against v2 can call
disconnect()without arguments. Fully backward compatible.
The mangled symbol names are identical (_ZN10Connection7connectEi, etc.) because
default values do not participate in name mangling.
Code diff¶
class Connection {
public:
- void connect(int timeout = 30);
- void configure(bool verbose = true, int retries = 3);
- void disconnect(int code);
+ void connect(int timeout = 60);
+ void configure(bool verbose, int retries = 5);
+ void disconnect(int code = 0);
};
Real Failure Demo¶
Severity: NONE (binary compatible)
Scenario: Compile app against v1 headers, swap in v2 .so.
# Build v1 library + app
g++ -shared -fPIC -g v1.cpp -o libfoo.so
g++ -g app.cpp -I. -L. -lfoo -Wl,-rpath,. -o app
./app
# → Parameter defaults demo (compiled against v1.hpp):
# →
# → Calling connect() with default timeout:
# → Compiled as connect(30) from v1 header
# → OK — v2 default is 60, but caller already passed 30
# →
# → Calling connect(45) with explicit timeout:
# → OK — explicit args are unaffected
# →
# → Calling configure() with defaults:
# → Compiled as configure(true, 3) from v1 header
# → OK — v2 removed verbose default, but caller already passed true
# → ...
# Swap in v2 (no recompile)
g++ -shared -fPIC -g v2.cpp -o libfoo.so
./app
# → Output is IDENTICAL — defaults were baked into the caller at compile time.
# → The v2 library receives the same arguments as v1.
Source break verification (partial — configure() with no args fails):
# Create a minimal source that includes only v2.hpp and calls configure()
cat > /tmp/source_break.cpp << 'SRC'
#include "v2.hpp"
int main() {
Connection conn;
conn.configure(); // no args — v2 requires explicit 'verbose'
return 0;
}
SRC
g++ -g /tmp/source_break.cpp -I. -L. -lfoo -Wl,-rpath,. -o /tmp/app_v2 2>&1
# → error: no matching function for call to 'Connection::configure()'
# → note: candidate expects 2 arguments, 0 provided
# (because 'verbose' lost its default in v2)
rm -f /tmp/source_break.cpp /tmp/app_v2
Reproduce with abicheck¶
g++ -shared -fPIC -g v1.cpp -o libfoo_v1.so
g++ -shared -fPIC -g v2.cpp -o libfoo_v2.so
abidw --out-file v1.xml libfoo_v1.so
abidw --out-file v2.xml libfoo_v2.so
abidiff v1.xml v2.xml
echo "exit: $?" # → 0 (no binary ABI change)
How to fix¶
No fix needed for binary compatibility. For source compatibility:
- Do not remove defaults from public headers in minor releases.
- If a default value must change, document it clearly — existing compiled binaries will silently continue using the old default until recompiled.
- Consider using overloaded functions instead of defaults for critical parameters where behavioral differences matter.
References¶
Source files¶
See also: Examples overview · All NO_CHANGE cases · Category: No Change.