IMPROVEMENTS:
1. Add explicit zero-argument overload to avoid SFINAE ambiguity
2. Require at least one argument (A1) for parameterized overloads
3. Better separation between direct initialization and aggregate initialization
BENEFITS:
- Clearer intent: zero-argument construction is explicitly handled
- Avoids potential SFINAE ambiguity when empty parameter pack is used
- More maintainable: easier to understand which overload is selected
- Consistent with modern C++ best practices for variadic templates
TECHNICAL DETAILS:
- Zero-arg overload: Always uses T() for value initialization
- One-or-more-arg overload: Uses SFINAE to choose between:
* T(args...) for types with matching constructor
* T{args...} for aggregate types or types with initializer_list ctor
This is a code quality improvement and does not fix any compilation issues,
but provides better template overload resolution.
ROOT CAUSE:
The allocate() function was incorrectly constructing objects during memory
allocation, violating C++ allocator requirements. MSVC's std::_Tree_node has
a deleted default constructor, causing compilation failure.
CHANGES:
- container_allocator::allocate() now only allocates raw memory without
constructing objects (removed mem::$new and ipc::construct calls)
- container_allocator::deallocate() now only frees memory without
destroying objects (removed mem::$delete and ipc::destroy_n calls)
WHY THIS FIXES THE ISSUE:
C++ allocator semantics require strict separation:
* allocate() -> raw memory allocation only
* construct() -> object construction with proper arguments
* destroy() -> object destruction
* deallocate() -> memory deallocation only
Standard containers (like std::map) call construct() with proper arguments
(key, value) to initialize nodes, not allocate(). Since std::_Tree_node in
MSVC has no default constructor (= delete), attempting to construct it
without arguments always fails.
Fixes MSVC 2017 compilation error:
error C2280: 'std::_Tree_node<...>::_Tree_node(void)':
attempting to reference a deleted function
- Add comprehensive documentation for shm::release(id), shm::remove(id), and shm::remove(name)
- release(id): Decrements ref count, cleans up memory and disk file when count reaches zero
- remove(id): Calls release(id) internally, then forces disk file cleanup (WARNING: do not use after release)
- remove(name): Only removes disk file, safe to use anytime
- Fix critical double-free bug in ShmTest test cases
- Problem: calling release(id) followed by remove(id) causes use-after-free crash
because release() already frees the id structure
- Solution: replace 'release(id); remove(id);' pattern with just 'remove(id)'
- Fixed tests: AcquireCreate, AcquireCreateOrOpen, GetMemory, GetMemoryNoSize,
RemoveById, SubtractReference
- Kept 'release(id); remove(name);' pattern unchanged (safe usage)
- Add explanatory comments in test code to prevent future misuse
Header changes (include/libipc/buffer.h):
- Rename: additional → mem_to_free (better semantic name)
- Add documentation comments explaining the parameter's purpose
- Clarifies that mem_to_free is passed to destructor instead of p
- Use case: when data pointer is offset into a larger allocation
Implementation changes (src/libipc/buffer.cpp):
- Update parameter name in constructor implementation
- No logic changes, just naming improvement
Test changes (test/test_buffer.cpp):
- Fix TEST_F(BufferTest, ConstructorWithMemToFree)
- Previous test caused crash: passed stack variable address to destructor
- New test correctly demonstrates the parameter's purpose:
* Allocate 100-byte block
* Use offset portion (bytes 25-75) as data
* Destructor receives original block pointer for proper cleanup
- Prevents double-free and invalid free errors
Semantic explanation:
buffer(data_ptr, size, destructor, mem_to_free)
On destruction:
destructor(mem_to_free ? mem_to_free : data_ptr, size)
This allows:
char* block = new char[100];
char* data = block + 25;
buffer buf(data, 50, my_free, block); // Frees 'block', not 'data'
- Change: byte_t const (& data)[N] → byte_t (& data)[N]
- Allows non-const byte arrays to be accepted by the constructor
- Fixes defect discovered by TEST_F(BufferTest, ConstructorFromByteArray)
- The const qualifier on array elements was too restrictive
- Keep char const & c unchanged as it's correct for single char reference