> PdfArray() is constructed, automatically PdfObject is constructed by the
> compiler.
> BUT PdfArray() and PdfObject are also destroyed automatically when the
> function terminates. This is because PdfArray() is constructed on the
> stack and not on the heap.
Nope. Things are copied at every level required as far as I can tell.
PLEASE post a DETAILED trace showing EXACTLY where you think the code
fails to make a copy and instead retains a reference to an existing object.
A debugger is a useful tool for this. Step through the construction
process. See where, EXACTLY, you think it goes wrong. Take note of the
program state at that point.
> The second argument is a temporary PdfArray instance. As GetKey expects
> a PdfObject the compiler creates a new PdfObject temporary with the
> PdfObject::PdfObject(const PdfArray&) constructor, and passes a const
> reference to that temporary to AddKey.
>
>
> Correct, temporary array.
Temporary PdfObject containing a _copy_ of the now-irrelevant PdfArray
by this stage, actually. We've already stopped using our PdfArray temporary.
> Now, in:
>
> void PdfDictionary::AddKey( const PdfName & identifier, const
> PdfObject & rObject )
>
> the passed PdfObject is explicitly copy-constructed into the internal
> key map:
>
> m_mapKeys[identifier] = new PdfObject( rObject );
>
>
>
> Correct, but rObject is still the temporary array.
No, it's a PdfObject containing a _copy_ of the temporary PdfArray we
created. See below, where I explain:
> operator new() calls PdfObject::PdfObject(const PdfObject&) to
> copy-construct the PdfObject. That copy-constructs the PdfVariant parent
> type first, which in turn explicitly copies the PdfArray it's storing a
> pointer to in its UVariant as a PdfDataType* pData, as you can see here:
See, PdfObject extends ("inherits") PdfVariant. And PdfVariant's
copy-constructor calls PdfVariant::operator=() which, if the variant is
of type ePdfDataType_Array **COPIES** the PdfArray.
> PdfVariant::PdfVariant( const PdfVariant & rhs )
> {
> Init();
> this->operator=(rhs);
> SetDirty( false );
> }
>
> const PdfVariant & PdfVariant::operator=( const PdfVariant & rhs )
> {
> Clear();
> rhs.DelayedLoad();
> m_eDataType = rhs.m_eDataType;
> switch( m_eDataType )
> {
> case ePdfDataType_Array:
> {
> if( rhs.m_Data.pData )
> m_Data.pData = new
> PdfArray( *(static_cast<PdfArray*>(rhs.m_Data.pData)) );
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
See ? The array got copied.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This expression says, reading from inside to outside:
- Look up the m_Data union member (type UVariant) of the to-be-copied
PdfVariant rhs, treating that union member as a pointer type.
- Interpret the pointer we retrieved as a PdfArray*
- Dereference the pointer, producing a PdfArray&
- Pass the PdfArray& that's the other variant's PdfArray to the
contructor for the new PdfArray
The new PdfArray's ctor calls operator=() (implicitly defined) which
copies the PdfArray and its bases.
Ah.
I think I see where the problem might be. The STL classes aren't really
meant to be base classes to be derived from. In particular, they don't
have virtual destructors. That point isn't an issue here, but I suspect
that perhaps PoDoFo's inheritance from std::vector<PdfObject> as a base
for PdfArray is still fundamentally the issue.
I'll bet Borland isn't generating a correct copy constructor. It'll be
doing a bitwise copy of PdfArray rather than calling
std::vector<PdfObject>::operator= , so the implementation-dependent
internal storage for the std::vector<PdfObject> base isn't being copied,
and is later freed unexpectedly out from under the copy of the
PdfArray's base.
Now, that could PERHAPS explain something, but it doesn't match your
explanation, where you say that there's a pointer stored to the old
PdfArray temporary. The one we've copy-constructed repeatedly. Either
your compiler is doing something totally batshit insane in the name of
"optimisation", you're mis-describing or misunderstanding things, I'm
misunderstanding your explanation, or there's something else going on.
I'm not going to waste any more time on this until or unless you provide
me with a decent trace of the problematic execution path with useful
specifics about what's happening. Vague and imprecise descriptions
aren't going to cut it at this point.
(Sorry, working with obsolete tools on an OS that's a horror to develop
C++ on makes me grumpy)
> Well it seems logical and should work if everything is deep copy
> constructed.
You know, you could be more specific there. "the stored array pointer" ?
What stored array pointer? Where? Which line of code? In which file?
What instance of what object stores this invalid pointer, and in what
member? When is that member intialized incorrectly, and by what
function? At what point in execution, EXACTLY, did it become invalid?
> > I adjusted this to:
> > PdfPagesTree::PdfPagesTree( PdfVecObjects* pParent )
> > : PdfElement( "Pages", pParent ),
> > m_cache( 0 )
> > {
> > PdfArray* kids_array = new PdfArray();
> > PdfObject* kids_object = new PdfObject(kids_array);
> > PdfObject* count_object = new
> > PdfObject( static_cast<pdf_int64>(0LL) );
> > GetObject()->GetDictionary().AddKey( "Kids", kids_object ); //
> > kids->Reference()
> > GetObject()->GetDictionary().AddKey( "Count", count_object );
> > }
> >
> Er, that's wrong. You're leaking memory all over the place, or you would
> be if the code worked at all. Once you resolve the overloads what that
> code actually does is construct a new heap-based PdfArray, then call:
>
> PdfObject::PdfObject(pdf_uint64)
>
> with it! Or, at least, it should if your compiler implements C++
> properly.
>
>
> Ok, this probably explains why I got error 2. But I'm not sure. If this
> constructor was actually called, the "NOT AN ARRAY" should have been
> thrown much earlier.
How about you CHECK instead of guessing? You have a debugger, right?
Even if not, you can introduce debugging code to test this sort of thing
pretty easily, rather than playing guessing games. According to the
standard what I described is what it does, and on a modern gcc that's
what it does. If you think Borland is doing something different it might
be wise to find out.
--
Craig Ringer
------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now. http://p.sf.net/sfu/bobj-july
_______________________________________________
Podofo-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/podofo-users