Skip to content

interop: add weak_virtual_ptr for std::weak_ptr - #100

Open
jll63 wants to merge 2 commits into
boostorg:developfrom
jll63:feature/weak-ptr
Open

interop: add weak_virtual_ptr for std::weak_ptr#100
jll63 wants to merge 2 commits into
boostorg:developfrom
jll63:feature/weak-ptr

Conversation

@jll63

@jll63 jll63 commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Closes #73.

Summary

Adds <boost/openmethod/interop/std_weak_ptr.hpp>, providing weak_virtual_ptr<Class>, an alias for virtual_ptr<std::weak_ptr<Class>>. It tracks an object with a std::weak_ptr and remembers its v-table pointer, so lock() returns a shared_virtual_ptr with no hash table lookup — it costs exactly std::weak_ptr::lock(). Remembering the vptr is safe: the weak pointer keeps the control block alive, so once the object is destroyed it stays expired for good.

It is a storage facility only:

  • constructed/assigned from a shared_virtual_ptr (copies the vptr; the class need not be polymorphic), from another weak_virtual_ptr (upcasts), or from a std::shared_ptr / std::weak_ptr (acquires the vptr; expired ⇒ null vptr);
  • lock(), expired(), use_count(), reset(), pointer(), vptr();
  • deliberately no get(), operator*, operator->, cast<>() or make_weak_virtual;
  • not usable as a virtual parameter, neither as virtual_<std::weak_ptr<T>> nor as weak_virtual_ptr<T> (by value, &, const&): validate_method_parameter specializations reject both with "a weak pointer cannot be a virtual parameter; call lock() first".
shared_virtual_ptr<Animal> animal = make_shared_virtual<Dog>();
weak_virtual_ptr<Animal> observer = animal;

std::cout << poke(observer.lock()) << "\n"; // bark

animal = nullptr;
std::cout << std::boolalpha << observer.expired() << "\n"; // true

Design notes

  • std::weak_ptr does not fit the generic smart-pointer specialization of virtual_ptr (it needs get(), operator* and a conversion to bool), so the specialization is written by hand. virtual_traits is deliberately not specialized for std::weak_ptr: that keeps IsSmartPtr false, which is what lets the hand-written specialization win over the generic one.
  • One generic change in core.hpp: the plain virtual_ptr's converting constructor and assignment from another virtual_ptr now also require the source to have get() (detail::has_get, a partially specialized constexpr bool variable template). A weak source is then a clean substitution failure instead of a hard error in the body, and std::is_constructible_v reports it correctly.

Tests and docs

  • test/test_weak_virtual_ptr.cpp: 7 cases over the 4 direct/indirect × vector/map registries, plus static_asserts on the allowed and rejected conversions.
  • test/compile_fail_weak_ptr_parameter.cpp and test/compile_fail_weak_virtual_ptr_parameter.cpp, one per rejected spelling.
  • "Weak Pointers" section in smart_pointers.adoc, ref_headers.adoc entries, and weak_lock / weak_virtual_ptr_alias tags in the smart_pointers.cpp snippet (referenced by the MrDocs comments).

Verified locally: gcc 13.3 Debug -Werror, full suite 162/162; clang 22 on the new tests, compile-fail tests and snippet. Both compile-fail tests report the intended static_assert as the first error on both compilers. Not verified: a MrDocs build (not installed here).

🤖 Generated with Claude Code

Closes boostorg#73.

Add <boost/openmethod/interop/std_weak_ptr.hpp>, providing weak_virtual_ptr<Class>,
an alias for virtual_ptr<std::weak_ptr<Class>>. It tracks an object with a
std::weak_ptr and remembers its v-table pointer, so that lock() returns a
shared_virtual_ptr without a hash table lookup. Remembering the vptr is safe:
the weak pointer keeps the control block alive, so once the object is destroyed
it stays expired for good.

It is a storage facility only. It is constructed from a shared_virtual_ptr (or
a std::shared_ptr or std::weak_ptr), converts to a weak_virtual_ptr to a base
class, and offers lock(), expired(), use_count(), reset(), pointer() and
vptr(). It cannot be dereferenced, and it cannot be used as a virtual
parameter - neither as virtual_<std::weak_ptr<T>> nor as weak_virtual_ptr<T> -
because the object may no longer exist; validate_method_parameter
specializations reject both with "a weak pointer cannot be a virtual parameter;
call lock() first".

std::weak_ptr does not fit the generic smart-pointer specialization of
virtual_ptr, which needs get(), operator* and a conversion to bool, so the
specialization is written by hand. virtual_traits is deliberately not
specialized for std::weak_ptr: that keeps IsSmartPtr false, which is what lets
the hand-written specialization win.

In core.hpp, the plain virtual_ptr's converting constructor and assignment from
another virtual_ptr now also require the source to have get() (detail::has_get),
so a weak source is a clean substitution failure instead of a hard error in the
body, and is_constructible reports it correctly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@cppalliance-bot

cppalliance-bot commented Sep 5, 2026

Copy link
Copy Markdown

An automated preview of the documentation is available at https://100.openmethod.prtest3.cppalliance.org/libs/openmethod/doc/html/index.html

If more commits are pushed to the pull request, the docs will rebuild at the same URL.

2026-09-05 20:26:23 UTC

… test

The dispatch test registered the static member functions of a local class
as override<> template arguments. That is valid C++17, but gcc before 13
rejects it ("has no linkage"), failing the gcc-10/11/12 and Cygwin 32-bit
jobs. Use namespace-scope function templates instead, as test_util.hpp's
poke_bear does.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.77%. Comparing base (5ec487c) to head (9ab25da).
⚠️ Report is 8 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop     #100      +/-   ##
===========================================
+ Coverage    93.46%   93.77%   +0.31%     
===========================================
  Files           22       23       +1     
  Lines         1653     1752      +99     
  Branches       500      512      +12     
===========================================
+ Hits          1545     1643      +98     
  Misses          64       64              
- Partials        44       45       +1     
Files with missing lines Coverage Δ
include/boost/openmethod/core.hpp 93.09% <ø> (ø)
include/boost/openmethod/interop/std_weak_ptr.hpp 100.00% <100.00%> (ø)

... and 3 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a6bf756...9ab25da. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

support std::weak_ptr

2 participants