Reputation: 3678
I am struggling to understand why there is such a difference in behavior across compilers and platforms.
Here is an extended example of http://kyungminlee.org/doc/minutiae/local_static_variable_shared_library.html.
CMakeLists.txt:
cmake_minimum_required(VERSION 3.7.2)
project(static_inline)
set(CMAKE_CXX_STANDARD 14)
add_library(lib SHARED collect.h collect.cpp)
target_compile_definitions(lib PRIVATE BUILD_DLL)
add_executable(static_inline main.cpp)
target_link_libraries(static_inline PRIVATE lib)
enable_testing()
add_test(NAME test.static_inline
COMMAND static_inline)
collect.h
#pragma once
#ifdef _WIN32
# define STATIC
# ifdef BUILD_DLL
# define EXPORT __declspec(dllexport)
# else
# define EXPORT __declspec(dllimport)
# endif
#else
# define STATIC static
# define EXPORT
#endif
// static will not compile on windows since static inline has internal linkage
EXPORT STATIC inline int collect(int x)
{
static int sum = 0;
sum += x;
return sum;
}
EXPORT int get_sum();
struct EXPORT foo
{
static inline int collect(int x)
{
static int sum = 0;
sum += x;
return sum;
}
int get_sum();
};
collect.cpp
#include "collect.h"
int get_sum()
{
return collect(0);
}
int foo::get_sum()
{
return collect(0);
}
main.cpp
#include "collect.h"
#include <iostream>
int main()
{
int num_from_inline_function = collect(10);
int num_from_inline_function2 = get_sum();
std::cout << "static inline collect: " << num_from_inline_function << std::endl;
std::cout << "get_sum: " << num_from_inline_function2 << std::endl;
int num_from_inline_static_member_function = foo::collect(10);
int num_from_inline_static_member_function2 = foo().get_sum();
std::cout << "static inline foo::collect: " << num_from_inline_static_member_function << std::endl;
std::cout << "foo::get_sum: " << num_from_inline_static_member_function2 << std::endl;
return !(num_from_inline_static_member_function == num_from_inline_static_member_function2 &&
num_from_inline_function == num_from_inline_static_member_function2);
}
MinGW-w64.
1: Test command: C:\dev\repos\static_inline\cmake-build-release-mingw-w64\static_inline.exe
1: Test timeout computed to be: 10000000
1: static inline collect: 10
1: get_sum: 0
1: static inline foo::collect: 10
1: foo::get_sum: 0
Failed
Clang
1: Test command: C:\dev\repos\static_inline\cmake-build-release-mingw-w64\static_inline.exe
1: Test timeout computed to be: 10000000
1: static inline collect: 10
1: get_sum: 0
1: static inline foo::collect: 10
1: foo::get_sum: 0
Failed
MSVC
1: Test command: C:\dev\repos\static_inline\cmake-build-release-visual-studio\static_inline.exe
1: Test timeout computed to be: 10000000
1: static inline collect: 10
1: get_sum: 10
1: static inline foo::collect: 10
1: foo::get_sum: 10
100% tests passed, 0 tests failed out of 1
GCC and Clang give the same output
1: Test command: /home/travis/build/ElDesalmado/static_inline_example/build/static_inline
1: Test timeout computed to be: 9.99988e+06
1: static inline collect: 10
1: get_sum: 0
1: static inline foo::collect: 10
1: foo::get_sum: 10
1/1 Test #1: test.static_inline ............... Passed 0.00 sec
100% tests passed, 0 tests failed out of 1
Results look somewhat consistent only on Ubuntu. On Windows only MSVC behaves differently. More over MSVC differs not only from MinGW and Clang, but also from GCC and Clang on Ubuntu.
I suppose for MSVC on Windows the result we see is because of the linker removes duplicate symbols of inlined functions and member functions:
Function-local static objects in all definitions of the same inline function (which may be implicitly inline) all refer to the same object defined in one translation unit.
2. What about static member inline functions with function-local static objects? Do They refer to the same object across translation units?
class __declspec(dllexport) counter
{
static int get() // implicitly inline
{
static int current = 0;
return current++;
}
};
Upvotes: 1
Views: 598
Reputation: 40063
With #define STATIC static
, the ::collect
that main
calls is simply a different function from the one that ::get_sum
calls, so I don’t know what other behavior you expect. This doesn’t apply to member functions, static or otherwise; static
means something completely different there, and the multiple definitions of foo
all define the same type with the same member functions.
Upvotes: 1