Commit c7e877b88b7e0c9a4608e16df777ded5dd8f6593

Authored by Jay Berkenbilt
1 parent ef2b84c6

Update documentation for PointerHolder transition

README-maintainer
... ... @@ -160,11 +160,16 @@ CODING RULES
160 160 it seems also for classes that are intended to be subclassed across
161 161 the shared library boundary.
162 162  
163   -* Put private member variables in PointerHolder<Members> for all
  163 +* Put private member variables in std::shared_ptr<Members> for all
164 164 public classes. Remember to use QPDF_DLL on ~Members(). Exception:
165   - indirection through PointerHolder<Members> is expensive, so don't do
166   - it for classes that are copied a lot, like QPDFObjectHandle and
167   - QPDFObject.
  165 + indirection through std::shared_ptr<Members> is expensive, so don't
  166 + do it for classes that are copied a lot, like QPDFObjectHandle and
  167 + QPDFObject. It may be possible to declare
  168 + std::shared_ptr<Members> m_ph;
  169 + Member* m;
  170 + with m = m_ph.get(), and then indirect through m in
  171 + performance-critical settings, though in 2022, std::shared_ptr is
  172 + sufficiently performant that this may not be worth it.
168 173  
169 174 * Traversal of objects is expensive. It's worth adding some complexity
170 175 to avoid needless traversals of objects.
... ...
... ... @@ -5,8 +5,7 @@ Next
5 5 * At next release, hide release-qpdf-10.6.3.0cmake* versions at readthedocs
6 6  
7 7 In order:
8   -* cmake
9   -* PointerHolder -> shared_ptr
  8 +* cmake -- remaining steps
10 9 * ABI including --json default is latest
11 10 * json v2
12 11  
... ... @@ -29,9 +28,6 @@ Misc
29 28 --show-encryption could potentially retry with this option if the
30 29 first time doesn't work. Then, with the file open, we can read the
31 30 encryption dictionary normally.
32   -* Go through README-maintainer "CODING RULES" and update --
33   - PointerHolder and other changes will make some of the rules
34   - obsolete.
35 31 * Have a warn in QPDF that passes its variable arguments onto QPDFExc
36 32 so you don't have to do warn(QPDFExc(...))
37 33  
... ... @@ -57,6 +53,7 @@ cmake
57 53 QPDF_DLL are public because QPDF_DLL_LOCAL makes the other things
58 54 private. See https://gcc.gnu.org/wiki/Visibility. Make sure this
59 55 is documented.
  56 + * Update "CODING RULES" in "README-maintainer" - search for QPDF_DLL
60 57 * Nice to have:
61 58 * Split qpdf.test into multiple tests
62 59 * Rework tests so that nothing is written into the source directory.
... ... @@ -500,103 +497,6 @@ Other notes:
500 497 way that works for the qpdf/qpdf repository as well since they are
501 498 very similar.
502 499  
503   -PointerHolder to std::shared_ptr
504   -================================
505   -
506   -To perform update:
507   -
508   -Cherry-pick pointerholder branch commit
509   -
510   -Upgrade just the library. This is not necessary, but it's an added
511   -check that the compatibility code works since it will show that tests,
512   -examples, and CLI will work properly with the upgraded APIs, which
513   -provides some assurance that other people will have a smooth time with
514   -their code.
515   -
516   -patrepl s/PointerHolder/std::shared_ptr/g {include,libqpdf}/qpdf/*.hh
517   -patrepl s/PointerHolder/std::shared_ptr/g libqpdf/*.cc
518   -patrepl s/make_pointer_holder/std::make_shared/g libqpdf/*.cc
519   -patrepl s/make_array_pointer_holder/QUtil::make_shared_array/g libqpdf/*.cc
520   -patrepl s,qpdf/std::shared_ptr,qpdf/PointerHolder, **/*.cc **/*.hh
521   -git restore include/qpdf/PointerHolder.hh
522   -cleanpatch
523   -
524   -Increase to POINTERHOLDER_TRANSITION=3
525   -
526   -make build_libqpdf -- no errors
527   -
528   -Drop back to POINTERHOLDER_TRANSITION=2
529   -
530   -make check -- everything passes
531   -
532   -Then upgrade everything else. It would work to just start here.
533   -
534   -Increase to POINTERHOLDER_TRANSITION=3
535   -
536   -patrepl s/PointerHolder/std::shared_ptr/g **/*.cc **/*.hh
537   -patrepl s/make_pointer_holder/std::make_shared/g **/*.cc
538   -patrepl s/make_array_pointer_holder/QUtil::make_shared_array/g **/*.cc
539   -patrepl s,qpdf/std::shared_ptr,qpdf/PointerHolder, **/*.cc **/*.hh
540   -git restore include/qpdf/PointerHolder.hh
541   -git restore libtests/pointer_holder.cc
542   -cleanpatch
543   -
544   -Remove all references to PointerHolder.hh from everything except
545   -public headers and pointer_holder.cc.
546   -
547   -make check -- everything passes
548   -
549   -Increase to POINTERHOLDER_TRANSITION=4
550   -
551   -Do a clean build and make check -- everything passes
552   -
553   -Final steps:
554   -
555   -* Change to POINTERHOLDER_TRANSITION=4
556   -* Check code formatting
557   -* std::shared_ptr<Members> m can be replaced with
558   - std::shared_ptr<Members> m_ph and Members* m if performance is critical
559   -* Could try Members indirection with Members* for QPDFObjectHandle
560   -
561   -When done:
562   -
563   -* Update the smart-pointers section of the manual in design.rst
564   -* Update comments in PointerHolder.hh
565   -
566   -PointerHolder in public API:
567   -
568   - PointerHolder<Buffer> Pl_Buffer::getBufferSharedPointer();
569   - PointerHolder<Buffer> QPDFWriter::getBufferSharedPointer();
570   - QUtil::read_file_into_memory(
571   - char const*, PointerHolder<char>&, unsigned long&)
572   - QPDFObjectHandle::addContentTokenFilter(
573   - PointerHolder<QPDFObjectHandle::TokenFilter>)
574   - QPDFObjectHandle::addTokenFilter(
575   - PointerHolder<QPDFObjectHandle::TokenFilter>)
576   - QPDFObjectHandle::newStream(
577   - QPDF*, PointerHolder<Buffer>)
578   - QPDFObjectHandle::parse(
579   - PointerHolder<InputSource>, std::string const&,
580   - QPDFTokenizer&, bool&, QPDFObjectHandle::StringDecrypter*, QPDF*)
581   - QPDFObjectHandle::replaceStreamData(
582   - PointerHolder<Buffer>, QPDFObjectHandle const&,
583   - QPDFObjectHandle const&)
584   - QPDFObjectHandle::replaceStreamData(
585   - PointerHolder<QPDFObjectHandle::StreamDataProvider>,
586   - QPDFObjectHandle const&, QPDFObjectHandle const&)
587   - QPDFTokenizer::expectInlineImage(
588   - PointerHolder<InputSource>)
589   - QPDFTokenizer::readToken(
590   - PointerHolder<InputSource>, std::string const&,
591   - bool, unsigned long)
592   - QPDF::processInputSource(
593   - PointerHolder<InputSource>, char const*)
594   - QPDFWriter::registerProgressReporter(
595   - PointerHolder<QPDFWriter::ProgressReporter>)
596   - QPDFEFStreamObjectHelper::createEFStream(
597   - QPDF&, PointerHolder<Buffer>)
598   - QPDFPageObjectHelper::addContentTokenFilter(
599   - PointerHolder<QPDFObjectHandle::TokenFilter>)
600 500  
601 501 ABI Changes
602 502 ===========
... ...
manual/design.rst
... ... @@ -53,13 +53,11 @@ or not if this information is needed. All access to objects deals with
53 53 this transparently. All memory management details are also handled by
54 54 the library.
55 55  
56   -The ``PointerHolder`` object is used internally by the library to deal
57   -with memory management. This is basically a smart pointer object very
58   -similar in spirit to C++-11's ``std::shared_ptr`` object, but predating
59   -it by several years. This library also makes use of a technique for
60   -giving fine-grained access to methods in one class to other classes by
61   -using public subclasses with friends and only private members that in
62   -turn call private methods of the containing class. See
  56 +Memory is managed mostly with ``std::shared_ptr`` object to minimize
  57 +explicit memory handling. This library also makes use of a technique
  58 +for giving fine-grained access to methods in one class to other
  59 +classes by using public subclasses with friends and only private
  60 +members that in turn call private methods of the containing class. See
63 61 ``QPDFObjectHandle::Factory`` as an example.
64 62  
65 63 The top-level qpdf class is ``QPDF``. A ``QPDF`` object represents a PDF
... ... @@ -68,13 +66,14 @@ files.
68 66  
69 67 The primary class for interacting with PDF objects is
70 68 ``QPDFObjectHandle``. Instances of this class can be passed around by
71   -value, copied, stored in containers, etc. with very low overhead.
72   -Instances of ``QPDFObjectHandle`` created by reading from a file will
73   -always contain a reference back to the ``QPDF`` object from which they
74   -were created. A ``QPDFObjectHandle`` may be direct or indirect. If
75   -indirect, the ``QPDFObject`` the ``PointerHolder`` initially points to
76   -is a null pointer. In this case, the first attempt to access the
77   -underlying ``QPDFObject`` will result in the ``QPDFObject`` being
  69 +value, copied, stored in containers, etc. with very low overhead. The
  70 +``QPDFObjectHandle`` object contains an internal shared pointer to an
  71 +underyling ``QPDFObject``. Instances of ``QPDFObjectHandle`` created
  72 +by reading from a file will always contain a reference back to the
  73 +``QPDF`` object from which they were created. A ``QPDFObjectHandle``
  74 +may be direct or indirect. If indirect, the ``QPDFObject`` shared
  75 +pointer is initially null. In this case, the first attempt to access
  76 +the underlying ``QPDFObject`` will result in the ``QPDFObject`` being
78 77 resolved via a call to the referenced ``QPDF`` instance. This makes it
79 78 essentially impossible to make coding errors in which certain things
80 79 will work for some PDF files and not for others based on which objects
... ... @@ -248,17 +247,18 @@ During this process, the &quot;``R``&quot; keyword is recognized and an indirect
248 247  
249 248 The ``QPDF::resolve()`` method, which is used to resolve an indirect
250 249 object, may be invoked from the ``QPDFObjectHandle`` class. It first
251   -checks a cache to see whether this object has already been read. If not,
252   -it reads the object from the PDF file and caches it. It the returns the
253   -resulting ``QPDFObjectHandle``. The calling object handle then replaces
254   -its ``PointerHolder<QDFObject>`` with the one from the newly returned
255   -``QPDFObjectHandle``. In this way, only a single copy of any direct
256   -object need exist and clients can access objects transparently without
257   -knowing or caring whether they are direct or indirect objects.
258   -Additionally, no object is ever read from the file more than once. That
259   -means that only the portions of the PDF file that are actually needed
260   -are ever read from the input file, thus allowing the qpdf package to
261   -take advantage of this important design goal of PDF files.
  250 +checks a cache to see whether this object has already been read. If
  251 +not, it reads the object from the PDF file and caches it. It the
  252 +returns the resulting ``QPDFObjectHandle``. The calling object handle
  253 +then replaces its ``std::shared_ptr<QDFObject>`` with the one from the
  254 +newly returned ``QPDFObjectHandle``. In this way, only a single copy
  255 +of any direct object need exist and clients can access objects
  256 +transparently without knowing or caring whether they are direct or
  257 +indirect objects. Additionally, no object is ever read from the file
  258 +more than once. That means that only the portions of the PDF file that
  259 +are actually needed are ever read from the input file, thus allowing
  260 +the qpdf package to take advantage of this important design goal of
  261 +PDF files.
262 262  
263 263 If the requested object is inside of an object stream, the object stream
264 264 itself is first read into memory. Then the tokenizer reads objects from
... ... @@ -762,40 +762,47 @@ Smart Pointers
762 762 --------------
763 763  
764 764 This section describes changes to the use of smart pointers that were
765   -made in qpdf 10.6.0 as well as some planned for 11.0.0.
  765 +made in qpdf 10.6.0 and 11.0.0.
766 766  
767   -Starting in qpdf 11, ``PointerHolder`` will be replaced with
  767 +In qpdf 11.0.0, ``PointerHolder`` was replaced with
768 768 ``std::shared_ptr`` in qpdf's public API. A backward-compatible
769   -``PointerHolder`` class will be provided that should make it possible
770   -for most code to remain unchanged. ``PointerHolder`` may eventually be
  769 +``PointerHolder`` class has been provided that makes it possible for
  770 +most code to remain unchanged. ``PointerHolder`` may eventually be
771 771 removed from qpdf entirely, but this will not happen for a while to
772 772 make it easier for people who need to support multiple versions of
773 773 qpdf.
774 774  
775   -The ``POINTERHOLDER_TRANSITION`` preprocessor symbol has been
776   -introduced to help people transition from ``PointerHolder`` to
777   -``std::shared_ptr``. After qpdf 11 is released, to prepare for a
778   -future qpdf without ``PointerHolder`` and to let them know that it is
779   -no longer needed, a warning will be issued if
780   -``<qpdf/PointerHolder.hh>`` is included, though it will be possible to
781   -suppress the warning by defining ``POINTERHOLDER_TRANSITION``. In
782   -10.6.0, there are some steps you can perform to prepare, but no action
783   -is required.
  775 +In 10.6.0, some enhancements were made to ``PointerHolder`` to ease
  776 +the transition. These intermediate steps are relevant only for
  777 +versions 10.6.0 through 10.6.3 but can still help with incremental
  778 +modification of code.
784 779  
785   -The remainder of this section describes how to prepare if you want to
786   -eliminate ``PointerHolder`` from your code or what to do if you want
787   -to stick with the old interfaces.
  780 +The ``POINTERHOLDER_TRANSITION`` preprocessor symbol was introduced in
  781 +qpdf 10.6.0 to help people transition from ``PointerHolder`` to
  782 +``std::shared_ptr``. If you don't define this, you will get a compiler
  783 +warning. Defining it to any value will suppress the warning. An
  784 +explanation appears below of the different possible values for this
  785 +symbol and what they mean.
788 786  
789   -Changes in 10.6.0
790   -~~~~~~~~~~~~~~~~~
  787 +Starting in qpdf 11.0.0, including ``<qpdf/PointerHolder.hh>`` defines
  788 +the symbol ``POINTERHOLDER_IS_SHARED_POINTER``. This can be used with
  789 +conditional compilation to make it possible to support different
  790 +versions of qpdf.
791 791  
792   -In qpdf 10.6.0, the following changes have been made to
793   -``PointerHolder`` to make its behavior closer to that of
794   -``std::shared_ptr``:
  792 +The rest of this section provides the details.
795 793  
796   -- ``get()`` has been added as an alternative to ``getPointer()``
  794 +Transitional Enhancements to PointerHolder
  795 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
797 796  
798   -- ``use_count()`` has been added as an alternative to ``getRefcount()``
  797 +In qpdf 10.6.0, some changes were to ``PointerHolder`` to make it
  798 +easier to prepare for the transition to ``std::shared_ptr``. These
  799 +enhancements also make it easier to incrementally upgrade your code.
  800 +The following changes were made to ``PointerHolder`` to make its
  801 +behavior closer to that of ``std::shared_ptr``:
  802 +
  803 +- ``get()`` was added as an alternative to ``getPointer()``
  804 +
  805 +- ``use_count()`` was added as an alternative to ``getRefcount()``
799 806  
800 807 - A new global helper function ``make_pointer_holder`` behaves
801 808 similarly to ``std::make_shared``, so you can use
... ... @@ -807,7 +814,7 @@ In qpdf 10.6.0, the following changes have been made to
807 814 counterpart to the newly added ``QUtil::make_shared_array`` method,
808 815 which does the same thing with a ``std::shared_ptr``.
809 816  
810   -``PointerHolder`` has had a long-standing bug: a ``const
  817 +``PointerHolder`` had a long-standing bug: a ``const
811 818 PointerHolder<T>`` would only provide a ``T const*`` with its
812 819 ``getPointer`` method. This is incorrect and is not how standard
813 820 library C++ smart pointers or regular pointers behave. The correct
... ... @@ -873,16 +880,23 @@ preprocessor symbol or other C++ coding techniques.
873 880 pointer. It also has the seldom-used ``getRefcount()`` method to get
874 881 the reference count. ``std::shared_ptr<T>`` has ``get()`` and
875 882 ``use_count()``. In qpdf 10.6, ``PointerHolder<T>`` also has
876   - would not be an issue unless you did this in your own code.
  883 + ``get()`` and ``use_count()``.
877 884  
878 885 Addressing the Differences
879 886 ~~~~~~~~~~~~~~~~~~~~~~~~~~
880 887  
881   -If you need to support versions of qpdf prior to qpdf 10.6, you don't
882   -*need* to take any action at this time, but it is recommended that you
883   -at least address the implicit constructor issue since this can be done
884   -without breaking backward compatibility. (Explicit construction of
885   -``PointerHolder<T>`` is and always has been allowed.)
  888 +If you are not ready to take action yet, you can ``#define
  889 +POINTERHOLDER_TRANSITION 0`` before including any qpdf header file or
  890 +add the definition of that symbol to your build. This will provide the
  891 +backward-compatible ``PointerHolder`` API without any deprecation
  892 +warnings. This should be a temporary measure as ``PointerHolder`` may
  893 +disappear in the future. If you need to be able to support newer and
  894 +older versions of qpdf, there are other options, explained below.
  895 +
  896 +Note that, even with ``0``, you should rebuild and test your code.
  897 +There may be compiler errors if you have containers of
  898 +``PointerHolder``, but most code should compile without any changes.
  899 +There are no uses of containers of ``PointerHolder`` in qpdf's API.
886 900  
887 901 There are two significant things you can do to minimize the impact of
888 902 switching from ``PointerHolder`` to ``std::shared_ptr``:
... ... @@ -908,31 +922,35 @@ without consulting this manual.
908 922 - meaning
909 923  
910 924 - - undefined
911   - - Same as ``0``, but starting with qpdf 11.0, issues a warning
  925 + - Same as ``0`` but issues a warning
912 926  
913 927 - - ``0``
914 928 - Provide a backward compatible ``PointerHolder`` and suppress
915   - all deprecation warnings
  929 + all deprecation warnings; supports all prior qpdf versions
916 930  
917 931 - - ``1``
918   - - Make the ``PointerHolder<T>(T*)`` constructor explicit
  932 + - Make the ``PointerHolder<T>(T*)`` constructor explicit;
  933 + resulting code supports all prior qpdf versions
919 934  
920 935 - - ``2``
921   - - Deprecate ``getPointer()`` and ``getRefcount()``
  936 + - Deprecate ``getPointer()`` and ``getRefcount()``; requires
  937 + qpdf 10.6.0 or later.
922 938  
923 939 - - ``3``
924   - - Starting with qpdf 11.0, deprecate all uses of ``PointerHolder``
  940 + - Deprecate all uses of ``PointerHolder``; requires qpdf 11.0.0
  941 + or later
925 942  
926 943 - - ``4``
927   - - Starting with qpdf 11.0, disable all functionality from
928   - ``qpdf/PointerHolder.hh`` so that ``#include``-ing it has no
929   - effect.
  944 + - Disable all functionality from ``qpdf/PointerHolder.hh`` so
  945 + that ``#include``-ing it has no effect other than defining
  946 + ``POINTERHOLDER_IS_SHARED_POINTER``; requires qpdf 11.0.0 or
  947 + later.
930 948  
931 949 Based on the above, here is a procedure for preparing your code. This
932 950 is the procedure that was used for the qpdf code itself.
933 951  
934   -If you need to support versions of qpdf prior to 10.6, you can still
935   -do these steps:
  952 +You can do these steps without breaking support for qpdf versions
  953 +before 10.6.0:
936 954  
937 955 - Find all occurrences of ``PointerHolder`` in the code. See whether
938 956 any of them can just be outright replaced with ``std::shared_ptr``
... ... @@ -974,8 +992,9 @@ do these steps:
974 992 auto p = std::unique_ptr<X[]>(new X[n]);
975 993  
976 994 - If a ``PointerHolder<T>`` can't be replaced with a standard library
977   - smart pointer, perhaps it can be declared using ``auto`` or
978   - ``decltype`` so that, when the qpdf API changes, your code will just
  995 + smart pointer because it is used with an older qpdf API call,
  996 + perhaps it can be declared using ``auto`` or ``decltype`` so that,
  997 + when building with a newer qpdf API changes, your code will just
979 998 need to be recompiled.
980 999  
981 1000 - ``#define POINTERHOLDER_TRANSITION 1`` to enable deprecation
... ... @@ -1000,55 +1019,18 @@ do these steps:
1000 1019 Other examples appear above.
1001 1020  
1002 1021 If you need to support older versions of qpdf than 10.6, this is as
1003   -far as you can go until qpdf 11 comes out.
1004   -
1005   -If you only need to support the latest version of qpdf, proceed as
1006   -follows:
1007   -
1008   -- ``#define POINTERHOLDER_TRANSITION 2`` to enable deprecation of
1009   - ``getPointer()`` and ``getRefcount()``
1010   -
1011   -- Replace ``getPointer()`` with ``get()`` and ``getRefcount()`` with
1012   - ``use_count()``. These methods were not present prior to 10.6.0.
  1022 +far as you can go without conditional compilation.
1013 1023  
1014   -When you have gotten your code to compile cleanly with
1015   -``POINTERHOLDER_TRANSITION=2``, you are well on your way to being
1016   -ready for eliminating ``PointerHolder`` entirely after qpdf 11 is
1017   -released.
1018   -
1019   -After qpdf 11 is out
1020   -~~~~~~~~~~~~~~~~~~~~
1021   -
1022   -In the 10.6 manual, this section represents a plan and is subject to
1023   -change. However, it has been tested in practice using a version of the
1024   -qpdf 11 ``PointerHolder`` on a branch, so it is likely to be accurate.
1025   -In the meantime, think of this as a preview.
1026   -
1027   -First, make sure you have done the steps in the 10.6 section. (Note:
1028   -once qpdf 11 comes out, the goal is to not have to migrate to 10.6
1029   -first, so it is likely that these sections will be combined.)
1030   -
1031   -If you are explicitly choosing to stick with the backward compatible
1032   -``PointerHolder`` for now, you should define
1033   -``POINTERHOLDER_TRANSITION`` to ``0`` to suppress the warning from
1034   -including ``qpdf/PointerHolder.hh``. Be aware that you may eventually
1035   -have to deal with the transition, though the intention is to leave the
1036   -compatibility layer in place for a while. You should rebuild and test
1037   -your code. There may be compiler errors if you have containers of
1038   -``PointerHolder``, but most code should compile without any changes.
1039   -Even if you have errors, use of ``auto`` or ``decltype`` may enable
1040   -you to write code that works with the old and new API without having
1041   -to use conditional compilation. The
1042   -``POINTERHOLDER_IS_SHARED_POINTER`` is defined in qpdf 11 if you
1043   -``#include <qpdf/PointerHolder.hh>``.
1044   -
1045   -If you want to support older versions of qpdf and still transition so
1046   -that the backward-compatible ``PointerHolder`` is not in use, you can
1047   -separate old code and new code by testing with the
  1024 +Starting in qpdf 11.0.0, including ``<qpdf/PointerHolder.hh>`` defines
  1025 +the symbol ``POINTERHOLDER_IS_SHARED_POINTER``. If you want to support
  1026 +older versions of qpdf and still transition so that the
  1027 +backward-compatible ``PointerHolder`` is not in use, you can separate
  1028 +old code and new code by testing with the
1048 1029 ``POINTERHOLDER_IS_SHARED_POINTER`` preprocessor symbol, as in
1049 1030  
1050 1031 .. code-block:: c++
1051 1032  
  1033 + #include <qpdf/PointerHolder.hh>
1052 1034 #ifdef POINTERHOLDER_IS_SHARED_POINTER
1053 1035 std::shared_ptr<X> x;
1054 1036 #else
... ... @@ -1060,6 +1042,7 @@ or
1060 1042  
1061 1043 .. code-block:: c++
1062 1044  
  1045 + #include <qpdf/PointerHolder.hh>
1063 1046 #ifdef POINTERHOLDER_IS_SHARED_POINTER
1064 1047 auto x_p = std::make_shared<X>();
1065 1048 X* x = x_p.get();
... ... @@ -1074,13 +1057,23 @@ If you don&#39;t need to support older versions of qpdf, you can proceed
1074 1057 with these steps without protecting changes with the preprocessor
1075 1058 symbol. Here are the remaining changes.
1076 1059  
1077   -- Make sure you have a clean build with ``POINTERHOLDER_TRANSITION``
1078   - set to ``2``. This means that you are using ``PointerHolder`` in a
1079   - manner that is API-compatible with ``std::shared_ptr`` in all cases
1080   - except for array pointers.
  1060 +- ``#define POINTERHOLDER_TRANSITION 2`` to enable deprecation of
  1061 + ``getPointer()`` and ``getRefcount()``
  1062 +
  1063 +- Replace ``getPointer()`` with ``get()`` and ``getRefcount()`` with
  1064 + ``use_count()``. These methods were not present prior to 10.6.0.
  1065 +
  1066 +When you have gotten your code to compile cleanly with
  1067 +``POINTERHOLDER_TRANSITION=2``, you are well on your way to being
  1068 +ready for eliminating ``PointerHolder`` entirely. The code at this
  1069 +point will not work with any qpdf version prior to 10.6.0.
  1070 +
  1071 +To support qpdf 11.0.0 and newer and remove ``PointerHolder`` from
  1072 +your code, continue with the following steps:
1081 1073  
1082 1074 - Replace all occurrences of ``PointerHolder`` with
1083   - ``std::shared_ptr`` except in ``#include <qpdf/PointerHolder.hh>``
  1075 + ``std::shared_ptr`` except in the literal statement ``#include
  1076 + <qpdf/PointerHolder.hh>``
1084 1077  
1085 1078 - Replace all occurrences of ``make_pointer_holder`` with
1086 1079 ``std::make_shared``
... ...