[poppler] Branch 'better_object' - cpp/poppler-document.cpp cpp/poppler-page.cpp glib/poppler-action.cc glib/poppler-attachment.cc glib/poppler-document.cc glib/poppler-input-stream.cc glib/poppler-input-stream.h glib/poppler-movie.cc glib/poppler-page.cc glib/poppler-structure-element.cc poppler/Annot.cc poppler/Annot.h poppler/Array.cc poppler/Array.h poppler/CairoFontEngine.cc poppler/CairoOutputDev.cc poppler/Catalog.cc poppler/Catalog.h poppler/CMap.cc poppler/DCTStream.cc poppler/Dict.cc poppler/Dict.h poppler/FileSpec.cc poppler/FileSpec.h poppler/FontInfo.cc poppler/Form.cc poppler/Form.h poppler/Function.cc poppler/Gfx.cc poppler/GfxFont.cc poppler/GfxFont.h poppler/Gfx.h poppler/GfxState.cc poppler/Hints.cc poppler/JBIG2Stream.cc poppler/JPEG2000Stream.cc poppler/Lexer.cc poppler/Lexer.h poppler/Linearization.cc poppler/Link.cc poppler/Movie.cc poppler/Movie.h poppler/Object.cc poppler/Object.h poppler/OptionalContent.cc poppler/Outline.cc poppler/Page.cc poppler/Page.h popp ler/PageLabelInfo.cc poppler/PageTransition.cc poppler/Parser.cc poppler/Parser.h poppler/PDFDoc.cc poppler/PDFDoc.h poppler/PopplerCache.cc poppler/PopplerCache.h poppler/PSOutputDev.cc poppler/Rendition.cc poppler/SecurityHandler.cc poppler/Sound.cc poppler/Sound.h poppler/SplashOutputDev.cc poppler/StdinPDFDocBuilder.cc poppler/Stream.cc poppler/Stream.h poppler/StructElement.cc poppler/StructTreeRoot.cc poppler/ViewerPreferences.cc poppler/XRef.cc poppler/XRef.h qt4/src qt4/tests qt5/src qt5/tests test/pdf-fullrewrite.cc utils/pdfinfo.cc utils/pdftohtml.cc utils/pdftotext.cc utils/pdfunite.cc

Albert Astals Cid aacid at kemper.freedesktop.org
Mon May 8 22:53:34 UTC 2017


 cpp/poppler-document.cpp            |   14 
 cpp/poppler-page.cpp                |    5 
 glib/poppler-action.cc              |   27 
 glib/poppler-attachment.cc          |    4 
 glib/poppler-document.cc            |   30 
 glib/poppler-input-stream.cc        |   10 
 glib/poppler-input-stream.h         |    4 
 glib/poppler-movie.cc               |    5 
 glib/poppler-page.cc                |   13 
 glib/poppler-structure-element.cc   |   37 
 poppler/Annot.cc                    | 1779 ++++++++++++++----------------------
 poppler/Annot.h                     |   25 
 poppler/Array.cc                    |   34 
 poppler/Array.h                     |    8 
 poppler/CMap.cc                     |   10 
 poppler/CairoFontEngine.cc          |    4 
 poppler/CairoOutputDev.cc           |    3 
 poppler/Catalog.cc                  |  383 ++-----
 poppler/Catalog.h                   |    2 
 poppler/DCTStream.cc                |    8 
 poppler/Dict.cc                     |   49 
 poppler/Dict.h                      |   12 
 poppler/FileSpec.cc                 |  131 +-
 poppler/FileSpec.h                  |    4 
 poppler/FontInfo.cc                 |   41 
 poppler/Form.cc                     |  337 ++----
 poppler/Form.h                      |    2 
 poppler/Function.cc                 |  223 +---
 poppler/Gfx.cc                      |  767 +++++----------
 poppler/Gfx.h                       |   12 
 poppler/GfxFont.cc                  |  348 ++-----
 poppler/GfxFont.h                   |    2 
 poppler/GfxState.cc                 |  794 +++++-----------
 poppler/Hints.cc                    |   23 
 poppler/JBIG2Stream.cc              |    3 
 poppler/JPEG2000Stream.cc           |   15 
 poppler/Lexer.cc                    |   72 -
 poppler/Lexer.h                     |    5 
 poppler/Linearization.cc            |   56 -
 poppler/Link.cc                     |  195 +--
 poppler/Movie.cc                    |  112 --
 poppler/Movie.h                     |    2 
 poppler/Object.cc                   |   67 -
 poppler/Object.h                    |  153 +--
 poppler/OptionalContent.cc          |  144 --
 poppler/Outline.cc                  |   47 
 poppler/PDFDoc.cc                   |  371 ++-----
 poppler/PDFDoc.h                    |    6 
 poppler/PSOutputDev.cc              |  404 ++------
 poppler/Page.cc                     |  192 +--
 poppler/Page.h                      |   17 
 poppler/PageLabelInfo.cc            |   50 -
 poppler/PageTransition.cc           |   32 
 poppler/Parser.cc                   |   96 -
 poppler/Parser.h                    |    7 
 poppler/PopplerCache.cc             |   19 
 poppler/PopplerCache.h              |    2 
 poppler/Rendition.cc                |  168 +--
 poppler/SecurityHandler.cc          |   83 -
 poppler/Sound.cc                    |   38 
 poppler/Sound.h                     |    4 
 poppler/SplashOutputDev.cc          |   15 
 poppler/StdinPDFDocBuilder.cc       |    5 
 poppler/Stream.cc                   |  133 --
 poppler/Stream.h                    |   24 
 poppler/StructElement.cc            |  244 +---
 poppler/StructTreeRoot.cc           |   73 -
 poppler/ViewerPreferences.cc        |   42 
 poppler/XRef.cc                     |  404 +++-----
 poppler/XRef.h                      |   14 
 qt4/src/poppler-annotation-helper.h |   37 
 qt4/src/poppler-document.cc         |   11 
 qt4/src/poppler-form.cc             |    5 
 qt4/src/poppler-optcontent.cc       |   15 
 qt4/src/poppler-page.cc             |   16 
 qt4/src/poppler-private.h           |    4 
 qt4/tests/check_lexer.cpp           |   63 -
 qt4/tests/check_optcontent.cpp      |  114 --
 qt5/src/poppler-annotation-helper.h |   37 
 qt5/src/poppler-document.cc         |   11 
 qt5/src/poppler-form.cc             |    5 
 qt5/src/poppler-optcontent.cc       |   15 
 qt5/src/poppler-page.cc             |   14 
 qt5/src/poppler-private.h           |    4 
 qt5/tests/check_lexer.cpp           |   91 -
 qt5/tests/check_optcontent.cpp      |  114 --
 test/pdf-fullrewrite.cc             |   21 
 utils/pdfinfo.cc                    |   19 
 utils/pdftohtml.cc                  |   11 
 utils/pdftotext.cc                  |   22 
 utils/pdfunite.cc                   |  208 +---
 91 files changed, 3492 insertions(+), 5809 deletions(-)

New commits:
commit 23988e14cb7b364101090adb395db83f0ed4c267
Author: Albert Astals Cid <aacid at kde.org>
Date:   Tue May 9 00:38:07 2017 +0200

    New Object API
    
    Implement the move operators and copy construtor
    
    Almost all the init() functions are gone and we just have simple
    constructors now
    
    Also made free() public since you're not supposed to call it anymore,
    unless you're being evil and malloc'ing Objects like Array/Dict/XRef
    
    This has a huge reaction chain, most importantly we
    don't get objects by passing a pointer Object parameter, we
    just get the object as a return value, which is a much clearer API
     -  aobj->copy(&obj);
     +  obj = aobj->copy();
    before I was never sure what was being copied into what
    
    Comes with a huge diff, I probably made some mistake in the porting
    since there was lots of copy & paste involved

diff --git a/cpp/poppler-document.cpp b/cpp/poppler-document.cpp
index 35bbfa2a..c7c95317 100644
--- a/cpp/poppler-document.cpp
+++ b/cpp/poppler-document.cpp
@@ -85,10 +85,8 @@ document_private::document_private(byte_array *file_data,
     , raw_doc_data_length(0)
     , is_locked(false)
 {
-    Object obj;
-    obj.initNull();
     file_data->swap(doc_data);
-    MemStream *memstr = new MemStream(&doc_data[0], 0, doc_data.size(), &obj);
+    MemStream *memstr = new MemStream(&doc_data[0], 0, doc_data.size(), Object(objNull));
     GooString goo_owner_password(owner_password.c_str());
     GooString goo_user_password(user_password.c_str());
     doc = new PDFDoc(memstr, &goo_owner_password, &goo_user_password);
@@ -103,9 +101,7 @@ document_private::document_private(const char *file_data, int file_data_length,
     , raw_doc_data_length(file_data_length)
     , is_locked(false)
 {
-    Object obj;
-    obj.initNull();
-    MemStream *memstr = new MemStream(const_cast<char *>(raw_doc_data), 0, raw_doc_data_length, &obj);
+    MemStream *memstr = new MemStream(const_cast<char *>(raw_doc_data), 0, raw_doc_data_length, Object(objNull));
     GooString goo_owner_password(owner_password.c_str());
     GooString goo_user_password(user_password.c_str());
     doc = new PDFDoc(memstr, &goo_owner_password, &goo_user_password);
@@ -314,9 +310,8 @@ std::vector<std::string> document::info_keys() const
         return std::vector<std::string>();
     }
 
-    Object info;
-    if (!d->doc->getDocInfo(&info)->isDict()) {
-        info.free();
+    Object info = d->doc->getDocInfo();
+    if (!info.isDict()) {
         return std::vector<std::string>();
     }
 
@@ -326,7 +321,6 @@ std::vector<std::string> document::info_keys() const
         keys[i] = std::string(info_dict->getKey(i));
     }
 
-    info.free();
     return keys;
 }
 
diff --git a/cpp/poppler-page.cpp b/cpp/poppler-page.cpp
index b8927b80..a3f85069 100644
--- a/cpp/poppler-page.cpp
+++ b/cpp/poppler-page.cpp
@@ -172,11 +172,10 @@ ustring page::label() const
 page_transition* page::transition() const
 {
     if (!d->transition) {
-        Object o;
-        if (d->page->getTrans(&o)->isDict()) {
+        Object o = d->page->getTrans();
+        if (o.isDict()) {
             d->transition = new page_transition(&o);
         }
-        o.free();
     }
     return d->transition;
 }
diff --git a/glib/poppler-action.cc b/glib/poppler-action.cc
index 809fa586..e74d822d 100644
--- a/glib/poppler-action.cc
+++ b/glib/poppler-action.cc
@@ -431,9 +431,8 @@ find_annot_movie_for_action (PopplerDocument *document,
   if (link->hasAnnotRef ()) {
     Ref *ref = link->getAnnotRef ();
 
-    xref->fetch (ref->num, ref->gen, &annotObj);
+    annotObj = xref->fetch (ref->num, ref->gen);
   } else if (link->hasAnnotTitle ()) {
-    Object annots;
     GooString *title = link->getAnnotTitle ();
     int i;
 
@@ -441,39 +440,36 @@ find_annot_movie_for_action (PopplerDocument *document,
       Page *p = document->doc->getPage (i);
       if (!p) continue;
 
-      if (p->getAnnots (&annots)->isArray ()) {
+      Object annots = p->getAnnotsObject ();
+      if (annots.isArray ()) {
         int j;
 	GBool found = gFalse;
 
 	for (j = 0; j < annots.arrayGetLength () && !found; ++j) {
-          if (annots.arrayGet(j, &annotObj)->isDict()) {
-	    Object obj1;
-
-	    if (!annotObj.dictLookup ("Subtype", &obj1)->isName ("Movie")) {
-	      obj1.free ();
+          annotObj = annots.arrayGet(j);
+          if (annotObj.isDict()) {
+	    Object obj1 = annotObj.dictLookup ("Subtype");
+	    if (!obj1.isName ("Movie")) {
 	      continue;
 	    }
-	    obj1.free ();
 
-	    if (annotObj.dictLookup ("T", &obj1)->isString()) {
+	    obj1 = annotObj.dictLookup ("T");
+	    if (obj1.isString()) {
 	      GooString *t = obj1.getString ();
 
 	      if (title->cmp(t) == 0)
 	        found = gTrue;
 	    }
-	    obj1.free ();
 	  }
 	  if (!found)
-	    annotObj.free ();
+	    annotObj.setToNull ();
 	}
 	if (found) {
-	  annots.free ();
 	  break;
 	} else {
-          annotObj.free ();
+          annotObj.setToNull ();
 	}
       }
-      annots.free ();
     }
   }
 
@@ -486,7 +482,6 @@ find_annot_movie_for_action (PopplerDocument *document,
       annot = NULL;
     }
   }
-  annotObj.free ();
 
   return annot;
 }
diff --git a/glib/poppler-attachment.cc b/glib/poppler-attachment.cc
index 874bffb7..55936e78 100644
--- a/glib/poppler-attachment.cc
+++ b/glib/poppler-attachment.cc
@@ -67,7 +67,6 @@ poppler_attachment_dispose (GObject *obj)
 
   if (priv->obj_stream)
     {
-      priv->obj_stream->free();
       delete priv->obj_stream;
       priv->obj_stream = NULL;
     }
@@ -127,8 +126,7 @@ _poppler_attachment_new (FileSpec *emb_file)
   if (embFile->checksum () && embFile->checksum ()->getLength () > 0)
     attachment->checksum = g_string_new_len (embFile->checksum ()->getCString (),
                                              embFile->checksum ()->getLength ());
-  priv->obj_stream = new Object();
-  priv->obj_stream->initStream(embFile->stream());
+  priv->obj_stream = new Object(embFile->stream());
   // Copy the stream
   embFile->stream()->incRef();
 
diff --git a/glib/poppler-document.cc b/glib/poppler-document.cc
index 334f9b62..157a0484 100644
--- a/glib/poppler-document.cc
+++ b/glib/poppler-document.cc
@@ -230,7 +230,6 @@ poppler_document_new_from_data (char        *data,
                                 const char  *password,
                                 GError     **error)
 {
-  Object obj;
   PDFDoc *newDoc;
   MemStream *str;
   GooString *password_g;
@@ -240,8 +239,7 @@ poppler_document_new_from_data (char        *data,
   }
   
   // create stream
-  obj.initNull();
-  str = new MemStream(data, 0, length, &obj);
+  str = new MemStream(data, 0, length, Object(objNull));
 
   password_g = poppler_password_to_latin1(password);
   newDoc = new PDFDoc(str, password_g, password_g);
@@ -282,7 +280,6 @@ poppler_document_new_from_stream (GInputStream *stream,
                                   GCancellable *cancellable,
                                   GError      **error)
 {
-  Object obj;
   PDFDoc *newDoc;
   BaseStream *str;
   GooString *password_g;
@@ -300,12 +297,11 @@ poppler_document_new_from_stream (GInputStream *stream,
     return NULL;
   }
 
-  obj.initNull();
   if (stream_is_memory_buffer_or_local_file(stream)) {
-    str = new PopplerInputStream(stream, cancellable, 0, gFalse, 0, &obj);
+    str = new PopplerInputStream(stream, cancellable, 0, gFalse, 0, Object(objNull));
   } else {
     CachedFile *cachedFile = new CachedFile(new PopplerCachedFileLoader(stream, cancellable, length), new GooString());
-    str = new CachedFileStream(cachedFile, 0, gFalse, cachedFile->getLength(), &obj);
+    str = new CachedFileStream(cachedFile, 0, gFalse, cachedFile->getLength(), Object(objNull));
   }
 
   password_g = poppler_password_to_latin1(password);
@@ -2410,32 +2406,26 @@ get_optional_content_rbgroups (OCGs *ocg)
     int i, j;
 
     for (i = 0; i < rb->getLength (); ++i) {
-      Object obj;
       Array *rb_array;
       GList *group = NULL;
 
-      rb->get (i, &obj);
+      Object obj = rb->get (i);
       if (!obj.isArray ()) {
-        obj.free ();
 	continue;
       }
 
       rb_array = obj.getArray ();
       for (j = 0; j < rb_array->getLength (); ++j) {
-        Object ref;
 	OptionalContentGroup *oc;
 
-	rb_array->getNF (j, &ref);
+        Object ref = rb_array->getNF (j);
 	if (!ref.isRef ()) {
-	  ref.free ();
 	  continue;
 	}
 
 	oc = ocg->findOcgByRef (ref.getRef ());
 	group = g_list_prepend (group, oc);
-	ref.free ();
       }
-      obj.free ();
 
       groups = g_list_prepend (groups, group);
     }
@@ -2468,14 +2458,10 @@ get_optional_content_items_sorted (OCGs *ocg, Layer *parent, Array *order)
   int i;
 
   for (i = 0; i < order->getLength (); ++i) {
-    Object orderItem;
-      
-    order->get (i, &orderItem);
+    Object orderItem = order->get (i);
 
     if (orderItem.isDict ()) {
-      Object ref;
-      
-      order->getNF (i, &ref);
+      Object ref = order->getNF (i);
       if (ref.isRef ()) {
         OptionalContentGroup *oc = ocg->findOcgByRef (ref.getRef ());
 	Layer *layer = layer_new (oc);
@@ -2483,7 +2469,6 @@ get_optional_content_items_sorted (OCGs *ocg, Layer *parent, Array *order)
 	items = g_list_prepend (items, layer);
 	last_item = layer;
       }
-      ref.free ();
     } else if (orderItem.isArray () && orderItem.arrayGetLength () > 0) {
       if (!last_item) {
         last_item = layer_new (NULL);
@@ -2494,7 +2479,6 @@ get_optional_content_items_sorted (OCGs *ocg, Layer *parent, Array *order)
     } else if (orderItem.isString ()) {
       last_item->label = _poppler_goo_string_to_utf8 (orderItem.getString ());
     }
-    orderItem.free ();
   }
   
   return g_list_reverse (items);
diff --git a/glib/poppler-input-stream.cc b/glib/poppler-input-stream.cc
index e57e344b..cf7a5040 100644
--- a/glib/poppler-input-stream.cc
+++ b/glib/poppler-input-stream.cc
@@ -21,8 +21,8 @@
 #include "poppler-input-stream.h"
 
 PopplerInputStream::PopplerInputStream(GInputStream *inputStreamA, GCancellable *cancellableA,
-                                       Goffset startA, GBool limitedA, Goffset lengthA, Object *dictA)
-  : BaseStream(dictA, lengthA)
+                                       Goffset startA, GBool limitedA, Goffset lengthA, Object &&dictA)
+  : BaseStream(std::move(dictA), lengthA)
 {
   inputStream = (GInputStream *)g_object_ref(inputStreamA);
   cancellable = cancellableA ? (GCancellable *)g_object_ref(cancellableA) : NULL;
@@ -44,13 +44,13 @@ PopplerInputStream::~PopplerInputStream()
 }
 
 BaseStream *PopplerInputStream::copy() {
-  return new PopplerInputStream(inputStream, cancellable, start, limited, length, &dict);
+  return new PopplerInputStream(inputStream, cancellable, start, limited, length, dict.copy());
 }
 
 Stream *PopplerInputStream::makeSubStream(Goffset startA, GBool limitedA,
-                                          Goffset lengthA, Object *dictA)
+                                          Goffset lengthA, Object &&dictA)
 {
-  return new PopplerInputStream(inputStream, cancellable, startA, limitedA, lengthA, dictA);
+  return new PopplerInputStream(inputStream, cancellable, startA, limitedA, lengthA, std::move(dictA));
 }
 
 void PopplerInputStream::reset()
diff --git a/glib/poppler-input-stream.h b/glib/poppler-input-stream.h
index 39bbe01f..536487a4 100644
--- a/glib/poppler-input-stream.h
+++ b/glib/poppler-input-stream.h
@@ -31,11 +31,11 @@ class PopplerInputStream: public BaseStream {
 public:
 
   PopplerInputStream(GInputStream *inputStream, GCancellable *cancellableA,
-                     Goffset startA, GBool limitedA, Goffset lengthA, Object *dictA);
+                     Goffset startA, GBool limitedA, Goffset lengthA, Object &&dictA);
   ~PopplerInputStream();
   BaseStream *copy() override;
   Stream *makeSubStream(Goffset start, GBool limited,
-                        Goffset lengthA, Object *dictA) override;
+                        Goffset lengthA, Object &&dictA) override;
   StreamKind getKind() override { return strWeird; }
   void reset() override;
   void close() override;
diff --git a/glib/poppler-movie.cc b/glib/poppler-movie.cc
index 791cda76..1e82af70 100644
--- a/glib/poppler-movie.cc
+++ b/glib/poppler-movie.cc
@@ -84,11 +84,8 @@ _poppler_movie_new (Movie *poppler_movie)
 
   movie->filename = g_strdup (poppler_movie->getFileName()->getCString());
   if (poppler_movie->getShowPoster()) {
-    Object tmp;
-
-    poppler_movie->getPoster(&tmp);
+    Object tmp = poppler_movie->getPoster();
     movie->need_poster = (!tmp.isRef() && !tmp.isStream());
-    tmp.free();
   }
 
   movie->show_controls = poppler_movie->getActivationParameters()->showControls;
diff --git a/glib/poppler-page.cc b/glib/poppler-page.cc
index 3d63bfdd..a44edac6 100644
--- a/glib/poppler-page.cc
+++ b/glib/poppler-page.cc
@@ -184,12 +184,11 @@ poppler_page_get_transition (PopplerPage *page)
 {
   PageTransition *trans;
   PopplerPageTransition *transition;
-  Object obj;
-  
+
   g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
 
-  trans = new PageTransition (page->page->getTrans (&obj));
-  obj.free ();
+  Object obj = page->page->getTrans ();
+  trans = new PageTransition (&obj);
 
   if (!trans->isOk ()) {
     delete trans;
@@ -588,7 +587,6 @@ poppler_page_get_thumbnail_size (PopplerPage *page,
 				 int         *width,
 				 int         *height)
 {
-  Object thumb;
   Dict *dict;
   gboolean retval = FALSE;
 
@@ -596,10 +594,9 @@ poppler_page_get_thumbnail_size (PopplerPage *page,
   g_return_val_if_fail (width != NULL, FALSE);
   g_return_val_if_fail (height != NULL, FALSE);
 
-  page->page->getThumb (&thumb);
+  Object thumb = page->page->getThumb ();
   if (!thumb.isStream ())
     {
-      thumb.free ();
       return FALSE;
     }
 
@@ -611,8 +608,6 @@ poppler_page_get_thumbnail_size (PopplerPage *page,
       dict->lookupInt ("Height", "H", height))
     retval = TRUE;
 
-  thumb.free ();
-
   return retval;
 }
 
diff --git a/glib/poppler-structure-element.cc b/glib/poppler-structure-element.cc
index c6269992..70dfd507 100644
--- a/glib/poppler-structure-element.cc
+++ b/glib/poppler-structure-element.cc
@@ -1213,9 +1213,8 @@ convert_border_style (Object *object, PopplerStructureBorderStyle *values)
       g_assert (object->arrayGetLength () == 4);
       for (guint i = 0; i < 4; i++)
         {
-          Object item;
-          values[i] = name_to_enum<PopplerStructureBorderStyle> (object->arrayGet (i, &item));
-          item.free ();
+          Object item = object->arrayGet (i);
+          values[i] = name_to_enum<PopplerStructureBorderStyle> (&item);
         }
     }
   else
@@ -1261,9 +1260,7 @@ convert_doubles_array (Object *object, gdouble **values, guint *n_values)
 
   for (guint i = 0; i < *n_values; i++)
     {
-      Object item;
-      doubles[i] = object->arrayGet (i, &item)->getNum ();
-      item.free ();
+      doubles[i] = object->arrayGet (i).getNum ();
     }
 }
 
@@ -1273,16 +1270,9 @@ convert_color (Object *object, PopplerColor *color)
   g_assert (color != NULL);
   g_assert (object->isArray () && object->arrayGetLength () != 3);
 
-  Object item;
-
-  color->red = object->arrayGet (0, &item)->getNum () * 65535;
-  item.free ();
-
-  color->green = object->arrayGet (1, &item)->getNum () * 65535;
-  item.free ();
-
-  color->blue = object->arrayGet (2, &item)->getNum () * 65535;
-  item.free ();
+  color->red = object->arrayGet (0).getNum () * 65535;
+  color->green = object->arrayGet (1).getNum () * 65535;
+  color->blue = object->arrayGet (2).getNum () * 65535;
 }
 
 /**
@@ -1377,9 +1367,8 @@ poppler_structure_element_get_border_color (PopplerStructureElement *poppler_str
       // One color per side.
       for (guint i = 0; i < 4; i++)
         {
-          Object item;
-          convert_color (value->arrayGet (i, &item), &colors[i]);
-          item.free ();
+          Object item = value->arrayGet (i);
+          convert_color (&item, &colors[i]);
         }
     }
   else
@@ -1403,9 +1392,7 @@ convert_double_or_4_doubles (Object *object, gdouble *value)
       g_assert (object->arrayGetLength () == 4);
       for (guint i = 0; i < 4; i++)
         {
-          Object item;
-          value[i] = object->arrayGet (i, &item)->getNum ();
-          item.free ();
+          value[i] = object->arrayGet (i).getNum ();
         }
     }
   else
@@ -2175,16 +2162,14 @@ poppler_structure_element_get_table_headers (PopplerStructureElement *poppler_st
 
   for (guint i = 0; i < n_values; i++)
     {
-      Object item;
+      Object item = value->arrayGet (i);
 
-      if (value->arrayGet (i, &item)->isString ())
+      if (item.isString ())
         result[i] = _poppler_goo_string_to_utf8 (item.getString ());
       else if (item.isName ())
         result[i] = g_strdup (item.getName ());
       else
         g_assert_not_reached ();
-
-      item.free ();
     }
 
   return result;
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 73c2fe66..96a7e330 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -166,10 +166,10 @@ const char* convertAnnotLineEndingStyle(AnnotLineEndingStyle style) {
 }
 
 static AnnotExternalDataType parseAnnotExternalData(Dict* dict) {
-  Object obj1;
   AnnotExternalDataType type;
 
-  if (dict->lookup("Subtype", &obj1)->isName()) {
+  Object obj1 = dict->lookup("Subtype");
+  if (obj1.isName()) {
     const char *typeName = obj1.getName();
 
     if (!strcmp(typeName, "Markup3D")) {
@@ -180,7 +180,6 @@ static AnnotExternalDataType parseAnnotExternalData(Dict* dict) {
   } else {
     type = annotExternalDataMarkupUnknown;
   }
-  obj1.free();
 
   return type;
 }
@@ -190,14 +189,10 @@ PDFRectangle *parseDiffRectangle(Array *array, PDFRectangle *rect) {
   if (array->getLength() == 4) {
     // deltas
     Object obj1;
-    double dx1 = (array->get(0, &obj1)->isNum() ? obj1.getNum() : 0);
-    obj1.free();
-    double dy1 = (array->get(1, &obj1)->isNum() ? obj1.getNum() : 0);
-    obj1.free();
-    double dx2 = (array->get(2, &obj1)->isNum() ? obj1.getNum() : 0);
-    obj1.free();
-    double dy2 = (array->get(3, &obj1)->isNum() ? obj1.getNum() : 0);
-    obj1.free();
+    double dx1 = (obj1 = array->get(0), obj1.isNum() ? obj1.getNum() : 0);
+    double dy1 = (obj1 = array->get(1), obj1.isNum() ? obj1.getNum() : 0);
+    double dx2 = (obj1 = array->get(2), obj1.isNum() ? obj1.getNum() : 0);
+    double dy2 = (obj1 = array->get(3), obj1.isNum() ? obj1.getNum() : 0);
 
     // checking that the numbers are valid (i.e. >= 0),
     // and that applying the differences still give us a valid rect
@@ -215,10 +210,10 @@ PDFRectangle *parseDiffRectangle(Array *array, PDFRectangle *rect) {
 }
 
 static LinkAction* getAdditionalAction(Annot::AdditionalActionsType type, Object *additionalActions, PDFDoc *doc) {
-  Object additionalActionsObject;
-  LinkAction *linkAction = NULL;
+  LinkAction *linkAction = nullptr;
+  Object additionalActionsObject = additionalActions->fetch(doc->getXRef());
 
-  if (additionalActions->fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
+  if (additionalActionsObject.isDict()) {
     const char *key = (type == Annot::actionCursorEntering ? "E" :
                        type == Annot::actionCursorLeaving ?  "X" :
                        type == Annot::actionMousePressed ?   "D" :
@@ -230,37 +225,29 @@ static LinkAction* getAdditionalAction(Annot::AdditionalActionsType type, Object
                        type == Annot::actionPageVisible ?   "PV" :
                        type == Annot::actionPageInvisible ? "PI" : NULL);
 
-    Object actionObject;
-
-    if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
+    Object actionObject = additionalActionsObject.dictLookup(key);
+    if (actionObject.isDict())
       linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
-    actionObject.free();
   }
 
-  additionalActionsObject.free();
-
   return linkAction;
 }
 
 static LinkAction* getFormAdditionalAction(Annot::FormAdditionalActionsType type, Object *additionalActions, PDFDoc *doc) {
-  Object additionalActionsObject;
-  LinkAction *linkAction = NULL;
+  LinkAction *linkAction = nullptr;
+  Object additionalActionsObject = additionalActions->fetch(doc->getXRef());
 
-  if (additionalActions->fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
+  if (additionalActionsObject.isDict()) {
     const char *key = (type == Annot::actionFieldModified ?  "K" :
                        type == Annot::actionFormatField ?    "F" :
                        type == Annot::actionValidateField ?  "V" :
                        type == Annot::actionCalculateField ? "C" : NULL);
 
-    Object actionObject;
-
-    if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
+    Object actionObject = additionalActionsObject.dictLookup(key);
+    if (actionObject.isDict())
       linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
-    actionObject.free();
   }
 
-  additionalActionsObject.free();
-
   return linkAction;
 }
 
@@ -271,7 +258,8 @@ static LinkAction* getFormAdditionalAction(Annot::FormAdditionalActionsType type
 AnnotBorderEffect::AnnotBorderEffect(Dict *dict) {
   Object obj1;
 
-  if (dict->lookup("S", &obj1)->isName()) {
+  obj1 = dict->lookup("S");
+  if (obj1.isName()) {
     const char *effectName = obj1.getName();
 
     if (!strcmp(effectName, "C"))
@@ -281,14 +269,13 @@ AnnotBorderEffect::AnnotBorderEffect(Dict *dict) {
   } else {
     effectType = borderEffectNoEffect;
   }
-  obj1.free();
 
-  if ((dict->lookup("I", &obj1)->isNum()) && effectType == borderEffectCloudy) {
+  obj1 = dict->lookup("I");
+  if (obj1.isNum() && effectType == borderEffectCloudy) {
     intensity = obj1.getNum();
   } else {
     intensity = 0;
   }
-  obj1.free();
 }
 
 //------------------------------------------------------------------------
@@ -351,22 +338,21 @@ void AnnotPath::parsePathArray(Array *array) {
   tempCoords = (AnnotCoord **) gmallocn (tempLength, sizeof(AnnotCoord *));
   memset(tempCoords, 0, tempLength * sizeof(AnnotCoord *));
   for (int i = 0; i < tempLength && correct; i++) {
-    Object obj1;
     double x = 0, y = 0;
 
-    if (array->get(i * 2, &obj1)->isNum()) {
+    Object obj1 = array->get(i * 2);
+    if (obj1.isNum()) {
       x = obj1.getNum();
     } else {
       correct = gFalse;
     }
-    obj1.free();
 
-    if (array->get((i * 2) + 1, &obj1)->isNum()) {
+    obj1 = array->get((i * 2) + 1);
+    if (obj1.isNum()) {
       y = obj1.getNum();
     } else {
       correct = gFalse;
     }
-    obj1.free();
 
     if (!correct) {
       for (int j = i - 1; j >= 0; j--)
@@ -424,16 +410,14 @@ AnnotQuadrilaterals::AnnotQuadrilaterals(Array *array, PDFRectangle *rect) {
 
     for (i = 0; i < quadsLength; i++) {
       for (int j = 0; j < 8; j++) {
-        Object obj;
-        if (array->get(i * 8 + j, &obj)->isNum()) {
+        Object obj = array->get(i * 8 + j);
+        if (obj.isNum()) {
           quadArray[j] = obj.getNum();
         } else {
             correct = gFalse;
-	    obj.free();
 	    error (errSyntaxError, -1, "Invalid QuadPoint in annot");
 	    break;
         }
-        obj.free();
       }
 
       if (!correct)
@@ -540,13 +524,11 @@ GBool AnnotBorder::parseDashArray(Object *dashObj) {
 
   // TODO: check not all zero (Line Dash Pattern Page 217 PDF 8.1)
   for (int i = 0; i < tempLength && i < DASH_LIMIT && correct; i++) {
-    Object obj1;
-
-    if (dashObj->arrayGet(i, &obj1)->isNum()) {
+    Object obj1 = dashObj->arrayGet(i);
+    if (obj1.isNum()) {
       tempDash[i] = obj1.getNum();
 
       correct = tempDash[i] >= 0;
-      obj1.free();
     }
   }
 
@@ -583,30 +565,30 @@ AnnotBorderArray::AnnotBorderArray(Array *array) {
   if (arrayLength == 3 || arrayLength == 4) {
     // implementation note 81 in Appendix H.
 
-    if (array->get(0, &obj1)->isNum())
+    obj1 = array->get(0);
+    if (obj1.isNum())
       horizontalCorner = obj1.getNum();
     else
       correct = gFalse;
-    obj1.free();
 
-    if (array->get(1, &obj1)->isNum())
+    obj1 = array->get(1);
+    if (obj1.isNum())
       verticalCorner = obj1.getNum();
     else
       correct = gFalse;
-    obj1.free();
 
-    if (array->get(2, &obj1)->isNum())
+    obj1 = array->get(2);
+    if (obj1.isNum())
       width = obj1.getNum();
     else
       correct = gFalse;
-    obj1.free();
 
     if (arrayLength == 4) {
-      if (array->get(3, &obj1)->isArray())
+      obj1 = array->get(3);
+      if (obj1.isArray())
         correct = parseDashArray(&obj1);
       else
         correct = gFalse;
-      obj1.free();
     }
   } else {
     correct = gFalse;
@@ -617,21 +599,22 @@ AnnotBorderArray::AnnotBorderArray(Array *array) {
   }
 }
 
-void AnnotBorderArray::writeToObject(XRef *xref, Object *obj1) const {
-  Object obj2;
-
-  obj1->initArray(xref);
-  obj1->arrayAdd(obj2.initReal(horizontalCorner));
-  obj1->arrayAdd(obj2.initReal(verticalCorner));
-  obj1->arrayAdd(obj2.initReal(width));
+Object AnnotBorderArray::writeToObject(XRef *xref) const {
+  Array *borderArray = new Array(xref);
+  borderArray->add(Object(horizontalCorner));
+  borderArray->add(Object(verticalCorner));
+  borderArray->add(Object(width));
 
   if (dashLength > 0) {
-    Object obj3;
+    Array *a = new Array(xref);
 
-    obj1->arrayAdd(obj3.initArray(xref));
     for (int i = 0; i < dashLength; i++)
-      obj3.arrayAdd(obj2.initReal(dash[i]));
+      a->add(Object(dash[i]));
+
+    borderArray->add(Object(a));
   }
+
+  return Object(borderArray);
 }
 
 //------------------------------------------------------------------------
@@ -650,8 +633,8 @@ AnnotBorderBS::AnnotBorderBS(Dict *dict) {
   // that behaviour by veryifying both entries exist
   // otherwise we set the borderWidth to 0
   // --jrmuizel
-  dict->lookup("W", &obj1);
-  dict->lookup("S", &obj2);
+  obj1 = dict->lookup("W");
+  obj2 = dict->lookup("S");
   if (obj1.isNum() && obj2.isName()) {
     const char *styleName = obj2.getName();
 
@@ -673,13 +656,11 @@ AnnotBorderBS::AnnotBorderBS(Dict *dict) {
   } else {
     width = 0;
   }
-  obj2.free();
-  obj1.free();
 
   if (style == borderDashed) {
-    if (dict->lookup("D", &obj1)->isArray())
+    obj1 = dict->lookup("D");
+  if (obj1.isArray())
       parseDashArray(&obj1);
-    obj1.free();
 
     if (!dash) {
       dashLength = 1;
@@ -706,19 +687,18 @@ const char *AnnotBorderBS::getStyleName() const {
   return "S";
 }
 
-void AnnotBorderBS::writeToObject(XRef *xref, Object *obj1) const {
-  Object obj2;
-
-  obj1->initDict(xref);
-  obj1->dictSet("W", obj2.initReal(width));
-  obj1->dictSet("S", obj2.initName(getStyleName()));
+Object AnnotBorderBS::writeToObject(XRef *xref) const {
+  Dict *dict = new Dict(xref);
+  dict->set("W", Object(width));
+  dict->set("S", Object(objName, getStyleName()));
   if (style == borderDashed && dashLength > 0) {
-    Object obj3;
+    Array *a = new Array(xref);
 
-    obj1->dictSet("D", obj3.initArray(xref));
     for (int i = 0; i < dashLength; i++)
-      obj3.arrayAdd(obj2.initReal(dash[i]));
+      a->add(Object(dash[i]));
+    dict->set("D", Object(a));
   }
+  return Object(dict);
 }
 
 //------------------------------------------------------------------------
@@ -763,9 +743,8 @@ AnnotColor::AnnotColor(Array *array, int adjust) {
     length = 4;
 
   for (i = 0; i < length; i++) {
-    Object obj1;
-
-    if (array->get(i, &obj1)->isNum()) {
+    Object obj1 = array->get(i);
+    if (obj1.isNum()) {
       values[i] = obj1.getNum();
 
       if (values[i] < 0 || values[i] > 1)
@@ -773,7 +752,6 @@ AnnotColor::AnnotColor(Array *array, int adjust) {
     } else {
       values[i] = 0;
     }
-    obj1.free();
   }
 
   if (adjust != 0)
@@ -797,16 +775,14 @@ void AnnotColor::adjustColor(int adjust) {
   }
 }
 
-void AnnotColor::writeToObject(XRef *xref, Object *obj1) const {
-  Object obj2;
-  int i;
-
+Object AnnotColor::writeToObject(XRef *xref) const {
   if (length == 0) {
-    obj1->initNull(); // Transparent (no color)
+    return Object(objNull); // Transparent (no color)
   } else {
-    obj1->initArray(xref);
-    for (i = 0; i < length; ++i)
-      obj1->arrayAdd( obj2.initReal( values[i] ) );
+    Array *a = new Array(xref);
+    for (int i = 0; i < length; ++i)
+      a->add( Object( values[i] ) );
+    return Object(a);
   }
 }
 
@@ -817,7 +793,8 @@ void AnnotColor::writeToObject(XRef *xref, Object *obj1) const {
 AnnotIconFit::AnnotIconFit(Dict* dict) {
   Object obj1;
 
-  if (dict->lookup("SW", &obj1)->isName()) {
+  obj1 = dict->lookup("SW");
+  if (obj1.isName()) {
     const char *scaleName = obj1.getName();
 
     if(!strcmp(scaleName, "B")) {
@@ -832,9 +809,9 @@ AnnotIconFit::AnnotIconFit(Dict* dict) {
   } else {
     scaleWhen = scaleAlways;
   }
-  obj1.free();
 
-  if (dict->lookup("S", &obj1)->isName()) {
+  obj1 = dict->lookup("S");
+  if (obj1.isName()) {
     const char *scaleName = obj1.getName();
 
     if(!strcmp(scaleName, "A")) {
@@ -845,14 +822,12 @@ AnnotIconFit::AnnotIconFit(Dict* dict) {
   } else {
     scale = scaleProportional;
   }
-  obj1.free();
 
-  if (dict->lookup("A", &obj1)->isArray() && obj1.arrayGetLength() == 2) {
+  obj1 = dict->lookup("A");
+  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
     Object obj2;
-    (obj1.arrayGet(0, &obj2)->isNum() ? left = obj2.getNum() : left = 0);
-    obj2.free();
-    (obj1.arrayGet(1, &obj2)->isNum() ? bottom = obj2.getNum() : bottom = 0);
-    obj2.free();
+    (obj2 = obj1.arrayGet(0), obj2.isNum() ? left = obj2.getNum() : left = 0);
+    (obj2 = obj1.arrayGet(1), obj2.isNum() ? bottom = obj2.getNum() : bottom = 0);
 
     if (left < 0 || left > 1)
       left = 0.5;
@@ -863,14 +838,13 @@ AnnotIconFit::AnnotIconFit(Dict* dict) {
   } else {
     left = bottom = 0.5;
   }
-  obj1.free();
 
-  if (dict->lookup("FB", &obj1)->isBool()) {
+  obj1 = dict->lookup("FB");
+  if (obj1.isBool()) {
     fullyBounds = obj1.getBool();
   } else {
     fullyBounds = gFalse;
   }
-  obj1.free();
 }
 
 //------------------------------------------------------------------------
@@ -881,55 +855,54 @@ AnnotAppearance::AnnotAppearance(PDFDoc *docA, Object *dict) {
   assert(dict->isDict());
   doc = docA;
   xref = docA->getXRef();
-  dict->copy(&appearDict);
+  appearDict = dict->copy();
 }
 
 AnnotAppearance::~AnnotAppearance() {
-  appearDict.free();
 }
 
-void AnnotAppearance::getAppearanceStream(AnnotAppearanceType type, const char *state, Object *dest) {
-  Object apData, stream;
-  apData.initNull();
+Object AnnotAppearance::getAppearanceStream(AnnotAppearanceType type, const char *state) {
+  Object apData;
 
   // Obtain dictionary or stream associated to appearance type
   switch (type) {
   case appearRollover:
-    if (appearDict.dictLookupNF("R", &apData)->isNull())
-      appearDict.dictLookupNF("N", &apData);
+    apData = appearDict.dictLookupNF("R");
+    if (apData.isNull())
+      apData = appearDict.dictLookupNF("N");
     break;
   case appearDown:
-    if (appearDict.dictLookupNF("D", &apData)->isNull())
-      appearDict.dictLookupNF("N", &apData);
+    apData = appearDict.dictLookupNF("D");
+    if (apData.isNull())
+      apData = appearDict.dictLookupNF("N");
     break;
   case appearNormal:
-    appearDict.dictLookupNF("N", &apData);
+    apData = appearDict.dictLookupNF("N");
     break;
   }
 
-  dest->initNull();
+  Object res;
   if (apData.isDict() && state)
-    apData.dictLookupNF(state, dest);
+    res = apData.dictLookupNF(state);
   else if (apData.isRef())
-    apData.copy(dest);
-  apData.free();
+    res = apData.copy();
+
+  return res;
 }
 
 GooString * AnnotAppearance::getStateKey(int i) {
-  Object obj1;
   GooString * res = NULL;
-  if (appearDict.dictLookupNF("N", &obj1)->isDict())
+  Object obj1 = appearDict.dictLookupNF("N");
+  if (obj1.isDict())
     res = new GooString(obj1.dictGetKey(i));
-  obj1.free();
   return res;
 }
 
 int AnnotAppearance::getNumStates() {
-  Object obj1;
   int res = 0;
-  if (appearDict.dictLookupNF("N", &obj1)->isDict())
+  Object obj1 = appearDict.dictLookupNF("N");
+  if (obj1.isDict())
     res = obj1.dictGetLength();
-  obj1.free();
   return res;
 }
 
@@ -943,15 +916,13 @@ GBool AnnotAppearance::referencesStream(Object *stateObj, Ref refToStream) {
   } else if (stateObj->isDict()) { // Test each value
     const int size = stateObj->dictGetLength();
     for (int i = 0; i < size; ++i) {
-      Object obj1;
-      stateObj->dictGetValNF(i, &obj1);
+      Object obj1 = stateObj->dictGetValNF(i);
       if (obj1.isRef()) {
         Ref r = obj1.getRef();
         if (r.num == refToStream.num && r.gen == refToStream.gen) {
           return gTrue;
         }
       }
-      obj1.free();
     }
   }
   return gFalse; // Not found
@@ -963,21 +934,18 @@ GBool AnnotAppearance::referencesStream(Ref refToStream) {
   GBool found;
 
   // Scan each state's ref/subdictionary
-  appearDict.dictLookupNF("N", &obj1);
+  obj1 = appearDict.dictLookupNF("N");
   found = referencesStream(&obj1, refToStream);
-  obj1.free();
   if (found)
     return gTrue;
 
-  appearDict.dictLookupNF("R", &obj1);
+  obj1 = appearDict.dictLookupNF("R");
   found = referencesStream(&obj1, refToStream);
-  obj1.free();
   if (found)
     return gTrue;
 
-  appearDict.dictLookupNF("D", &obj1);
+  obj1 = appearDict.dictLookupNF("D");
   found = referencesStream(&obj1, refToStream);
-  obj1.free();
   return found;
 }
 
@@ -1011,27 +979,22 @@ void AnnotAppearance::removeStateStreams(Object *obj1) {
   } else if (obj1->isDict()) {
     const int size = obj1->dictGetLength();
     for (int i = 0; i < size; ++i) {
-      Object obj2;
-      obj1->dictGetValNF(i, &obj2);
+      Object obj2 = obj1->dictGetValNF(i);
       if (obj2.isRef()) {
         removeStream(obj2.getRef());
       }
-      obj2.free();
     }
   }
 }
 
 void AnnotAppearance::removeAllStreams() {
   Object obj1;
-  appearDict.dictLookupNF("N", &obj1);
+  obj1 = appearDict.dictLookupNF("N");
   removeStateStreams(&obj1);
-  obj1.free();
-  appearDict.dictLookupNF("R", &obj1);
+  obj1 = appearDict.dictLookupNF("R");
   removeStateStreams(&obj1);
-  obj1.free();
-  appearDict.dictLookupNF("D", &obj1);
+  obj1 = appearDict.dictLookupNF("D");
   removeStateStreams(&obj1);
-  obj1.free();
 }
 
 //------------------------------------------------------------------------
@@ -1041,14 +1004,15 @@ void AnnotAppearance::removeAllStreams() {
 AnnotAppearanceCharacs::AnnotAppearanceCharacs(Dict *dict) {
   Object obj1;
 
-  if (dict->lookup("R", &obj1)->isInt()) {
+  obj1 = dict->lookup("R");
+  if (obj1.isInt()) {
     rotation = obj1.getInt();
   } else {
     rotation = 0;
   }
-  obj1.free();
 
-  if (dict->lookup("BC", &obj1)->isArray()) {
+  obj1 = dict->lookup("BC");
+  if (obj1.isArray()) {
     Array *colorComponents = obj1.getArray();
     if (colorComponents->getLength() > 0) {
       borderColor = new AnnotColor(colorComponents);
@@ -1058,9 +1022,9 @@ AnnotAppearanceCharacs::AnnotAppearanceCharacs(Dict *dict) {
   } else {
     borderColor = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("BG", &obj1)->isArray()) {
+  obj1 = dict->lookup("BG");
+  if (obj1.isArray()) {
     Array *colorComponents = obj1.getArray();
     if (colorComponents->getLength() > 0) {
       backColor = new AnnotColor(colorComponents);
@@ -1070,42 +1034,41 @@ AnnotAppearanceCharacs::AnnotAppearanceCharacs(Dict *dict) {
   } else {
     backColor = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("CA", &obj1)->isString()) {
+  obj1 = dict->lookup("CA");
+  if (obj1.isString()) {
     normalCaption = new GooString(obj1.getString());
   } else {
     normalCaption = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("RC", &obj1)->isString()) {
+  obj1 = dict->lookup("RC");
+  if (obj1.isString()) {
     rolloverCaption = new GooString(obj1.getString());
   } else {
     rolloverCaption = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("AC", &obj1)->isString()) {
+  obj1 = dict->lookup("AC");
+  if (obj1.isString()) {
     alternateCaption = new GooString(obj1.getString());
   } else {
     alternateCaption = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("IF", &obj1)->isDict()) {
+  obj1 = dict->lookup("IF");
+  if (obj1.isDict()) {
     iconFit = new AnnotIconFit(obj1.getDict());
   } else {
     iconFit = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("TP", &obj1)->isInt()) {
+  obj1 = dict->lookup("TP");
+  if (obj1.isInt()) {
     position = (AnnotAppearanceCharacsTextPos) obj1.getInt();
   } else {
     position = captionNoIcon;
   }
-  obj1.free();
 }
 
 AnnotAppearanceCharacs::~AnnotAppearanceCharacs() {
@@ -1185,24 +1148,20 @@ double AnnotAppearanceBBox::getPageYMax() const {
 //------------------------------------------------------------------------
 
 Annot::Annot(PDFDoc *docA, PDFRectangle *rectA) {
-  Object obj1;
 
   refCnt = 1;
   flags = flagUnknown;
   type = typeUnknown;
 
-  obj1.initArray (docA->getXRef());
-  Object obj2;
-  obj1.arrayAdd (obj2.initReal (rectA->x1));
-  obj1.arrayAdd (obj2.initReal (rectA->y1));
-  obj1.arrayAdd (obj2.initReal (rectA->x2));
-  obj1.arrayAdd (obj2.initReal (rectA->y2));
-  obj2.free ();
+  Array *a = new Array(docA->getXRef());
+  a->add(Object(rectA->x1));
+  a->add(Object(rectA->y1));
+  a->add(Object(rectA->x2));
+  a->add(Object(rectA->y2));
 
-  annotObj.initDict (docA->getXRef());
-  annotObj.dictSet ("Type", obj2.initName ("Annot"));
-  annotObj.dictSet ("Rect", &obj1);
-  // obj1 is owned by the dict
+  annotObj = Object(new Dict(docA->getXRef()));
+  annotObj.dictSet ("Type", Object(objName, "Annot"));
+  annotObj.dictSet ("Rect", Object(a));
 
   ref = docA->getXRef()->addIndirectObject (&annotObj);
 
@@ -1214,7 +1173,8 @@ Annot::Annot(PDFDoc *docA, Dict *dict) {
   hasRef = false;
   flags = flagUnknown;
   type = typeUnknown;
-  annotObj.initDict (dict);
+  dict->incRef();
+  annotObj = Object(dict);
   initialize (docA, dict);
 }
 
@@ -1228,12 +1188,13 @@ Annot::Annot(PDFDoc *docA, Dict *dict, Object *obj) {
   }
   flags = flagUnknown;
   type = typeUnknown;
-  annotObj.initDict (dict);
+  dict->incRef();
+  annotObj = Object(dict);
   initialize (docA, dict);
 }
 
 void Annot::initialize(PDFDoc *docA, Dict *dict) {
-  Object apObj, asObj, obj1, obj2;
+  Object apObj, asObj, obj1;
 
   ok = gTrue;
   doc = docA;
@@ -1244,20 +1205,17 @@ void Annot::initialize(PDFDoc *docA, Dict *dict) {
   appearBuf = NULL;
   fontSize = 0;
 
-  appearance.initNull();
+  appearance.setToNull();
 
   //----- parse the rectangle
   rect = new PDFRectangle();
-  if (dict->lookup("Rect", &obj1)->isArray() && obj1.arrayGetLength() == 4) {
+  obj1 = dict->lookup("Rect");
+  if (obj1.isArray() && obj1.arrayGetLength() == 4) {
     Object obj2;
-    (obj1.arrayGet(0, &obj2)->isNum() ? rect->x1 = obj2.getNum() : rect->x1 = 0);
-    obj2.free();
-    (obj1.arrayGet(1, &obj2)->isNum() ? rect->y1 = obj2.getNum() : rect->y1 = 0);
-    obj2.free();
-    (obj1.arrayGet(2, &obj2)->isNum() ? rect->x2 = obj2.getNum() : rect->x2 = 1);
-    obj2.free();
-    (obj1.arrayGet(3, &obj2)->isNum() ? rect->y2 = obj2.getNum() : rect->y2 = 1);
-    obj2.free();
+    (obj2 = obj1.arrayGet(0), obj2.isNum() ? rect->x1 = obj2.getNum() : rect->x1 = 0);
+    (obj2 = obj1.arrayGet(1), obj2.isNum() ? rect->y1 = obj2.getNum() : rect->y1 = 0);
+    (obj2 = obj1.arrayGet(2), obj2.isNum() ? rect->x2 = obj2.getNum() : rect->x2 = 1);
+    (obj2 = obj1.arrayGet(3), obj2.isNum() ? rect->y2 = obj2.getNum() : rect->y2 = 1);
 
     if (rect->x1 > rect->x2) {
       double t = rect->x1;
@@ -1276,56 +1234,54 @@ void Annot::initialize(PDFDoc *docA, Dict *dict) {
     error(errSyntaxError, -1, "Bad bounding box for annotation");
     ok = gFalse;
   }
-  obj1.free();
 
-  if (dict->lookup("Contents", &obj1)->isString()) {
+  obj1 = dict->lookup("Contents");
+  if (obj1.isString()) {
     contents = obj1.getString()->copy();
   } else {
     contents = new GooString();
   }
-  obj1.free();
 
   // Note: This value is overwritten by Annots ctor
-  if (dict->lookupNF("P", &obj1)->isRef()) {
+  obj1 = dict->lookupNF("P");
+  if (obj1.isRef()) {
     Ref ref = obj1.getRef();
 
     page = doc->getCatalog()->findPage (ref.num, ref.gen);
   } else {
     page = 0;
   }
-  obj1.free();
 
-  if (dict->lookup("NM", &obj1)->isString()) {
+  obj1 = dict->lookup("NM");
+  if (obj1.isString()) {
     name = obj1.getString()->copy();
   } else {
     name = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("M", &obj1)->isString()) {
+  obj1 = dict->lookup("M");
+  if (obj1.isString()) {
     modified = obj1.getString()->copy();
   } else {
     modified = NULL;
   }
-  obj1.free();
 
   //----- get the flags
-  if (dict->lookup("F", &obj1)->isInt()) {
+  obj1 = dict->lookup("F");
+  if (obj1.isInt()) {
     flags |= obj1.getInt();
   } else {
     flags = flagUnknown;
   }
-  obj1.free();
 
   //----- get the annotation appearance dictionary
-  dict->lookup("AP", &apObj);
+  apObj = dict->lookup("AP");
   if (apObj.isDict()) {
     appearStreams = new AnnotAppearance(doc, &apObj);
   }
-  apObj.free();
 
   //----- get the appearance state
-  dict->lookup("AS", &asObj);
+  asObj = dict->lookup("AS");
   if (asObj.isName()) {
     appearState = new GooString(asObj.getName());
   } else if (appearStreams && appearStreams->getNumStates() != 0) {
@@ -1340,11 +1296,10 @@ void Annot::initialize(PDFDoc *docA, Dict *dict) {
   if (!appearState) {
     appearState = new GooString("Off");
   }
-  asObj.free();
 
   //----- get the annotation appearance
   if (appearStreams) {
-    appearStreams->getAppearanceStream(AnnotAppearance::appearNormal, appearState->getCString(), &appearance);
+    appearance = appearStreams->getAppearanceStream(AnnotAppearance::appearNormal, appearState->getCString());
   }
 
   //----- parse the border style
@@ -1352,27 +1307,27 @@ void Annot::initialize(PDFDoc *docA, Dict *dict) {
   // the border shall be drawn as a solid line with a width of 1 point. But acroread
   // seems to ignore the Border entry for annots that can't have a BS entry. So, we only
   // follow this rule for annots tha can have a BS entry.
-  if (dict->lookup("Border", &obj1)->isArray())
+  obj1 = dict->lookup("Border");
+  if (obj1.isArray())
     border = new AnnotBorderArray(obj1.getArray());
   else
     border = NULL;
-  obj1.free();
 
-  if (dict->lookup("C", &obj1)->isArray()) {
+  obj1 = dict->lookup("C");
+  if (obj1.isArray()) {
     color = new AnnotColor(obj1.getArray());
   } else {
     color = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("StructParent", &obj1)->isInt()) {
+  obj1 = dict->lookup("StructParent");
+  if (obj1.isInt()) {
     treeKey = obj1.getInt();
   } else {
     treeKey = 0;
   }
-  obj1.free();
 
-  dict->lookupNF("OC", &oc);
+  oc = dict->lookupNF("OC");
 
 #if MULTITHREADED
   gInitMutex(&mutex);
@@ -1391,8 +1346,6 @@ void Annot::setRect(PDFRectangle *rect) {
 }
 
 void Annot::setRect(double x1, double y1, double x2, double y2) {
-  Object obj1, obj2;
-
   if (x1 < x2) {
     rect->x1 = x1;
     rect->x2 = x2;
@@ -1409,13 +1362,13 @@ void Annot::setRect(double x1, double y1, double x2, double y2) {
     rect->y2 = y1;
   }
 
-  obj1.initArray (xref);
-  obj1.arrayAdd (obj2.initReal (rect->x1));
-  obj1.arrayAdd (obj2.initReal (rect->y1));
-  obj1.arrayAdd (obj2.initReal (rect->x2));
-  obj1.arrayAdd (obj2.initReal (rect->y2));
+  Array *a = new Array(xref);
+  a->add(Object(rect->x1));
+  a->add(Object(rect->y1));
+  a->add(Object(rect->x2));
+  a->add(Object(rect->y2));
 
-  update("Rect", &obj1);
+  update("Rect", Object(a));
   invalidateAppearance();
 }
 
@@ -1423,19 +1376,17 @@ GBool Annot::inRect(double x, double y) const {
   return rect->contains(x, y);
 }
 
-void Annot::update(const char *key, Object *value) {
+void Annot::update(const char *key, Object &&value) {
   annotLocker();
   /* Set M to current time, unless we are updating M itself */
   if (strcmp(key, "M") != 0) {
     delete modified;
     modified = timeToDateString(NULL);
 
-    Object obj1;
-    obj1.initString (modified->copy());
-    annotObj.dictSet("M", &obj1);
+    annotObj.dictSet("M", Object(modified->copy()));
   }
 
-  annotObj.dictSet(const_cast<char*>(key), value);
+  annotObj.dictSet(const_cast<char*>(key), std::move(value));
   
   xref->setModifiedObject(&annotObj, ref);
 }
@@ -1455,9 +1406,7 @@ void Annot::setContents(GooString *new_content) {
     contents = new GooString();
   }
   
-  Object obj1;
-  obj1.initString(contents->copy());
-  update ("Contents", &obj1);
+  update ("Contents", Object(contents->copy()));
 }
 
 void Annot::setName(GooString *new_name) {
@@ -1470,9 +1419,7 @@ void Annot::setName(GooString *new_name) {
     name = new GooString();
   }
 
-  Object obj1;
-  obj1.initString(name->copy());
-  update ("NM", &obj1);
+  update ("NM", Object(name->copy()));
 }
 
 void Annot::setModified(GooString *new_modified) {
@@ -1484,17 +1431,13 @@ void Annot::setModified(GooString *new_modified) {
   else
     modified = new GooString();
 
-  Object obj1;
-  obj1.initString(modified->copy());
-  update ("M", &obj1);
+  update ("M", Object(modified->copy()));
 }
 
 void Annot::setFlags(Guint new_flags) {
   annotLocker();
-  Object obj1;
   flags = new_flags;
-  obj1.initInt(flags);
-  update ("F", &obj1);
+  update ("F", Object(int(flags)));
 }
 
 void Annot::setBorder(AnnotBorder *new_border) {
@@ -1502,9 +1445,8 @@ void Annot::setBorder(AnnotBorder *new_border) {
   delete border;
 
   if (new_border) {
-    Object obj1;
-    new_border->writeToObject(xref, &obj1);
-    update(new_border->getType() == AnnotBorder::typeArray ? "Border" : "BS", &obj1);
+    Object obj1 = new_border->writeToObject(xref);
+    update(new_border->getType() == AnnotBorder::typeArray ? "Border" : "BS", std::move(obj1));
     border = new_border;
   } else {
     border = NULL;
@@ -1517,9 +1459,8 @@ void Annot::setColor(AnnotColor *new_color) {
   delete color;
 
   if (new_color) {
-    Object obj1;
-    new_color->writeToObject(xref, &obj1);
-    update ("C", &obj1);
+    Object obj1 = new_color->writeToObject(xref);
+    update ("C", std::move(obj1));
     color = new_color;
   } else {
     color = NULL;
@@ -1530,19 +1471,18 @@ void Annot::setColor(AnnotColor *new_color) {
 void Annot::setPage(int pageIndex, GBool updateP) {
   annotLocker();
   Page *pageobj = doc->getPage(pageIndex);
-  Object obj1;
+  Object obj1(objNull);
 
   if (pageobj) {
     Ref pageRef = pageobj->getRef();
-    obj1.initRef(pageRef.num, pageRef.gen);
+    obj1 = Object(pageRef.num, pageRef.gen);
     page = pageIndex;
   } else {
-    obj1.initNull();
     page = 0;
   }
 
   if (updateP) {
-    update("P", &obj1);
+    update("P", std::move(obj1));
   }
 }
 
@@ -1557,16 +1497,13 @@ void Annot::setAppearanceState(const char *state) {
   delete appearBBox;
   appearBBox = NULL;
 
-  Object obj1;
-  obj1.initName(state);
-  update ("AS", &obj1);
+  update ("AS", Object(objName, state));
 
   // The appearance state determines the current appearance stream
-  appearance.free();
   if (appearStreams) {
-    appearStreams->getAppearanceStream(AnnotAppearance::appearNormal, appearState->getCString(), &appearance);
+    appearance = appearStreams->getAppearanceStream(AnnotAppearance::appearNormal, appearState->getCString());
   } else {
-    appearance.initNull();
+    appearance.setToNull();
   }
 }
 
@@ -1584,18 +1521,15 @@ void Annot::invalidateAppearance() {
   delete appearBBox;
   appearBBox = NULL;
 
-  appearance.free();
-  appearance.initNull();
+  appearance.setToNull();
 
-  Object obj1, obj2;
-  obj1.initNull();
-  if (!annotObj.dictLookup("AP", &obj2)->isNull())
-    update ("AP", &obj1); // Remove AP
-  obj2.free();
+  Object obj2 = annotObj.dictLookup("AP");
+  if (!obj2.isNull())
+    update ("AP", Object(objNull)); // Remove AP
 
-  if (!annotObj.dictLookup("AS", &obj2)->isNull())
-    update ("AS", &obj1); // Remove AS
-  obj2.free();
+  obj2 = annotObj.dictLookup("AS");
+  if (!obj2.isNull())
+    update ("AS", Object(objNull)); // Remove AS
 }
 
 double Annot::getXMin() {
@@ -1615,16 +1549,13 @@ double Annot::getYMax() {
 }
 
 void Annot::readArrayNum(Object *pdfArray, int key, double *value) {
-  Object valueObject;
-
-  pdfArray->arrayGet(key, &valueObject);
+  Object valueObject = pdfArray->arrayGet(key);
   if (valueObject.isNum()) {
     *value = valueObject.getNum();
   } else {
     *value = 0;
     ok = gFalse;
   }
-  valueObject.free();
 }
 
 void Annot::removeReferencedObjects() {
@@ -1654,8 +1585,6 @@ void Annot::decRefCnt() {
 }
 
 Annot::~Annot() {
-  annotObj.free();
-  
   delete rect;
   delete contents;
 
@@ -1667,7 +1596,6 @@ Annot::~Annot() {
 
   delete appearStreams;
   delete appearBBox;
-  appearance.free();
 
   if (appearState)
     delete appearState;
@@ -1678,8 +1606,6 @@ Annot::~Annot() {
   if (color)
     delete color;
 
-  oc.free();
-
 #if MULTITHREADED
     gDestroyMutex(&mutex);
 #endif
@@ -1804,74 +1730,66 @@ void Annot::drawCircleBottomRight(double cx, double cy, double r) {
   appearBuf->append("S\n");
 }
 
-void Annot::createForm(double *bbox, GBool transparencyGroup, Object *resDict, Object *aStream) {
-  Object obj1, obj2;
-  Object appearDict;
-
-  appearDict.initDict(xref);
-  appearDict.dictSet("Length", obj1.initInt(appearBuf->getLength()));
-  appearDict.dictSet("Subtype", obj1.initName("Form"));
-  obj1.initArray(xref);
-  obj1.arrayAdd(obj2.initReal(bbox[0]));
-  obj1.arrayAdd(obj2.initReal(bbox[1]));
-  obj1.arrayAdd(obj2.initReal(bbox[2]));
-  obj1.arrayAdd(obj2.initReal(bbox[3]));
-  appearDict.dictSet("BBox", &obj1);
+Object Annot::createForm(double *bbox, GBool transparencyGroup, Dict *resDict) {
+  Dict *appearDict = new Dict(xref);
+  appearDict->set("Length", Object(appearBuf->getLength()));
+  appearDict->set("Subtype", Object(objName, "Form"));
+
+  Array *a = new Array(xref);
+  a->add(Object(bbox[0]));
+  a->add(Object(bbox[1]));
+  a->add(Object(bbox[2]));
+  a->add(Object(bbox[3]));
+  appearDict->set("BBox", Object(a));
   if (transparencyGroup) {
-    Object transDict;
-    transDict.initDict(xref);
-    transDict.dictSet("S", obj1.initName("Transparency"));
-    appearDict.dictSet("Group", &transDict);
+    Dict *d = new Dict(xref);
+    d->set("S", Object(objName, "Transparency"));
+    appearDict->set("Group", Object(d));
   }
   if (resDict)
-    appearDict.dictSet("Resources", resDict);
+    appearDict->set("Resources", Object(resDict));
 
   MemStream *mStream = new MemStream(copyString(appearBuf->getCString()), 0,
-				     appearBuf->getLength(), &appearDict);
+				     appearBuf->getLength(), Object(appearDict));
   mStream->setNeedFree(gTrue);
-  aStream->initStream(mStream);
+  return Object(static_cast<Stream*>(mStream));
 }
 
-void Annot::createResourcesDict(const char *formName, Object *formStream,
+Dict *Annot::createResourcesDict(const char *formName, Object &&formStream,
 				const char *stateName,
-				double opacity, const char *blendMode,
-				Object *resDict) {
-  Object gsDict, stateDict, formDict, obj1;
-
-  gsDict.initDict(xref);
+				double opacity, const char *blendMode) {
+  Dict *gsDict = new Dict(xref);
   if (opacity != 1) {
-    gsDict.dictSet("CA", obj1.initReal(opacity));
-    gsDict.dictSet("ca", obj1.initReal(opacity));
+    gsDict->set("CA", Object(opacity));
+    gsDict->set("ca", Object(opacity));
   }
   if (blendMode)
-    gsDict.dictSet("BM", obj1.initName(blendMode));
-  stateDict.initDict(xref);
-  stateDict.dictSet(stateName, &gsDict);
-  formDict.initDict(xref);
-  formDict.dictSet(formName, formStream);
+    gsDict->set("BM", Object(objName, blendMode));
+  Dict *stateDict = new Dict(xref);
+  stateDict->set(stateName, Object(gsDict));
+  Dict *formDict = new Dict(xref);
+  formDict->set(formName, std::move(formStream));
+
+  Dict *resDict = new Dict(xref);
+  resDict->set("ExtGState", Object(stateDict));
+  resDict->set("XObject", Object(formDict));
 
-  resDict->initDict(xref);
-  resDict->dictSet("ExtGState", &stateDict);
-  resDict->dictSet("XObject", &formDict);
+  return resDict;
 }
 
-Object *Annot::getAppearanceResDict(Object *dest) {
+Object Annot::getAppearanceResDict() {
   Object obj1, obj2;
 
-  dest->initNull(); // Default value
-
   // Fetch appearance's resource dict (if any)
-  appearance.fetch(xref, &obj1);
+  obj1 = appearance.fetch(xref);
   if (obj1.isStream()) {
-    obj1.streamGetDict()->lookup("Resources", &obj2);
+    obj2 = obj1.streamGetDict()->lookup("Resources");
     if (obj2.isDict()) {
-      obj2.copy(dest);
+      return obj2;
     }
-    obj2.free();
   }
-  obj1.free();
 
-  return dest;
+  return Object(objNull);
 }
 
 GBool Annot::isVisible(GBool printing) {
@@ -1905,17 +1823,14 @@ int Annot::getRotation() const
 }
 
 void Annot::draw(Gfx *gfx, GBool printing) {
-  Object obj;
-
   annotLocker();
   if (!isVisible (printing))
     return;
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
       rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -1928,7 +1843,7 @@ AnnotPopup::AnnotPopup(PDFDoc *docA, PDFRectangle *rect) :
 
   type = typePopup;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("Popup"));
+  annotObj.dictSet ("Subtype", Object(objName, "Popup"));
   initialize (docA, annotObj.getDict());
 }
 
@@ -1939,41 +1854,34 @@ AnnotPopup::AnnotPopup(PDFDoc *docA, Dict *dict, Object *obj) :
 }
 
 AnnotPopup::~AnnotPopup() {
-  parent.free();
 }
 
 void AnnotPopup::initialize(PDFDoc *docA, Dict *dict) {
-  Object obj1;
-
-  if (!dict->lookupNF("Parent", &parent)->isRef()) {
-    parent.initNull();
+  parent = dict->lookupNF("Parent");
+  if (!parent.isRef()) {
+    parent.setToNull();
   }
 
-  if (dict->lookup("Open", &obj1)->isBool()) {
+  Object obj1 = dict->lookup("Open");
+  if (obj1.isBool()) {
     open = obj1.getBool();
   } else {
     open = gFalse;
   }
-  obj1.free();
 }
 
 void AnnotPopup::setParent(Object *parentA) {
-  parentA->copy(&parent);
-  update ("Parent", &parent);
+  update ("Parent", parentA->copy());
 }
 
 void AnnotPopup::setParent(Annot *parentA) {
-  Ref parentRef = parentA->getRef();
-  parent.initRef(parentRef.num, parentRef.gen);
-  update ("Parent", &parent);
+  const Ref parentRef = parentA->getRef();
+  update ("Parent", Object(parentRef.num, parentRef.gen));
 }
 
 void AnnotPopup::setOpen(GBool openA) {
-  Object obj1;
-
   open = openA;
-  obj1.initBool(open);
-  update ("Open", &obj1);
+  update ("Open", Object(open));
 }
 
 //------------------------------------------------------------------------
@@ -2006,50 +1914,52 @@ AnnotMarkup::~AnnotMarkup() {
 void AnnotMarkup::initialize(PDFDoc *docA, Dict *dict, Object *obj) {
   Object obj1, obj2;
 
-  if (dict->lookup("T", &obj1)->isString()) {
+  obj1 = dict->lookup("T");
+  if (obj1.isString()) {
     label = obj1.getString()->copy();
   } else {
     label = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("Popup", &obj1)->isDict() && dict->lookupNF("Popup", &obj2)->isRef()) {
+  obj1 = dict->lookup("Popup");
+  obj2 = dict->lookupNF("Popup");
+  if (obj1.isDict() && obj2.isRef()) {
     popup = new AnnotPopup(docA, obj1.getDict(), &obj2);
   } else {
     popup = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("CA", &obj1)->isNum()) {
+  obj1 = dict->lookup("CA");
+  if (obj1.isNum()) {
     opacity = obj1.getNum();
   } else {
     opacity = 1.0;
   }
-  obj1.free();
 
-  if (dict->lookup("CreationDate", &obj1)->isString()) {
+  obj1 = dict->lookup("CreationDate");
+  if (obj1.isString()) {
     date = obj1.getString()->copy();
   } else {
     date = NULL;
   }
-  obj1.free();
 
-  if (dict->lookupNF("IRT", &obj1)->isRef()) {
+  obj1 = dict->lookupNF("IRT");
+  if (obj1.isRef()) {
     inReplyTo = obj1.getRef();
   } else {
     inReplyTo.num = 0;
     inReplyTo.gen = 0;
   }
-  obj1.free();
 
-  if (dict->lookup("Subj", &obj1)->isString()) {
+  obj1 = dict->lookup("Subj");
+  if (obj1.isString()) {
     subject = obj1.getString()->copy();
   } else {
     subject = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("RT", &obj1)->isName()) {
+  obj1 = dict->lookup("RT");
+  if (obj1.isName()) {
     const char *replyName = obj1.getName();
 
     if (!strcmp(replyName, "R")) {
@@ -2062,14 +1972,13 @@ void AnnotMarkup::initialize(PDFDoc *docA, Dict *dict, Object *obj) {
   } else {
     replyTo = replyTypeR;
   }
-  obj1.free();
 
-  if (dict->lookup("ExData", &obj1)->isDict()) {
+  obj1 = dict->lookup("ExData");
+  if (obj1.isDict()) {
     exData = parseAnnotExternalData(obj1.getDict());
   } else {
     exData = annotExternalDataMarkupUnknown;
   }
-  obj1.free();
 }
 
 void AnnotMarkup::setLabel(GooString *new_label) {
@@ -2086,9 +1995,7 @@ void AnnotMarkup::setLabel(GooString *new_label) {
     label = new GooString();
   }
 
-  Object obj1;
-  obj1.initString(label->copy());
-  update ("T", &obj1);
+  update ("T", Object(label->copy()));
 }
 
 void AnnotMarkup::setPopup(AnnotPopup *new_popup) {
@@ -2105,11 +2012,8 @@ void AnnotMarkup::setPopup(AnnotPopup *new_popup) {
   delete popup;
 
   if (new_popup) {
-    Object obj1;
-    Ref popupRef = new_popup->getRef();
-
-    obj1.initRef (popupRef.num, popupRef.gen);
-    update ("Popup", &obj1);
+    const Ref popupRef = new_popup->getRef();
+    update ("Popup", Object(popupRef.num, popupRef.gen));
 
     new_popup->setParent(this);
     popup = new_popup;
@@ -2128,11 +2032,8 @@ void AnnotMarkup::setPopup(AnnotPopup *new_popup) {
 }
 
 void AnnotMarkup::setOpacity(double opacityA) {
-  Object obj1;
-
   opacity = opacityA;
-  obj1.initReal(opacity);
-  update ("CA", &obj1);
+  update ("CA", Object(opacity));
   invalidateAppearance();
 }
 
@@ -2144,9 +2045,7 @@ void AnnotMarkup::setDate(GooString *new_date) {
   else
     date = new GooString();
 
-  Object obj1;
-  obj1.initString(date->copy());
-  update ("CreationDate", &obj1);
+  update ("CreationDate", Object(date->copy()));
 }
 
 void AnnotMarkup::removeReferencedObjects() {
@@ -2167,12 +2066,10 @@ void AnnotMarkup::removeReferencedObjects() {
 
 AnnotText::AnnotText(PDFDoc *docA, PDFRectangle *rect) :
     AnnotMarkup(docA, rect) {
-  Object obj1;
-
   type = typeText;
   flags |= flagNoZoom | flagNoRotate;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("Text"));
+  annotObj.dictSet ("Subtype", Object(objName, "Text"));
   initialize (docA, annotObj.getDict());
 }
 
@@ -2191,24 +2088,25 @@ AnnotText::~AnnotText() {
 void AnnotText::initialize(PDFDoc *docA, Dict *dict) {
   Object obj1;
 
-  if (dict->lookup("Open", &obj1)->isBool())
+  obj1 = dict->lookup("Open");
+  if (obj1.isBool())
     open = obj1.getBool();
   else
     open = gFalse;
-  obj1.free();
 
-  if (dict->lookup("Name", &obj1)->isName()) {
+  obj1 = dict->lookup("Name");
+  if (obj1.isName()) {
     icon = new GooString(obj1.getName());
   } else {
     icon = new GooString("Note");
   }
-  obj1.free();
 
-  if (dict->lookup("StateModel", &obj1)->isString()) {
-    Object obj2;
+  obj1 = dict->lookup("StateModel");
+  if (obj1.isString()) {
     GooString *modelName = obj1.getString();
 
-    if (dict->lookup("State", &obj2)->isString()) {
+    Object obj2 = dict->lookup("State");
+    if (obj2.isString()) {
       GooString *stateName = obj2.getString();
 
       if (!stateName->cmp("Marked")) {
@@ -2231,7 +2129,6 @@ void AnnotText::initialize(PDFDoc *docA, Dict *dict) {
     } else {
       state = stateUnknown;
     }
-    obj2.free();
 
     if (!modelName->cmp("Marked")) {
       switch (state) {
@@ -2266,15 +2163,13 @@ void AnnotText::initialize(PDFDoc *docA, Dict *dict) {
   } else {
     state = stateUnknown;
   }
-  obj1.free();
 }
 
 void AnnotText::setOpen(GBool openA) {
   Object obj1;
 
   open = openA;
-  obj1.initBool(open);
-  update ("Open", &obj1);
+  update ("Open", Object(open));
 }
 
 void AnnotText::setIcon(GooString *new_icon) {
@@ -2289,9 +2184,7 @@ void AnnotText::setIcon(GooString *new_icon) {
     icon = new GooString("Note");
   }
 
-  Object obj1;
-  obj1.initName (icon->getCString());
-  update("Name", &obj1);
+  update("Name", Object(objName, icon->getCString()));
   invalidateAppearance();
 }
 
@@ -2540,7 +2433,6 @@ void AnnotText::setIcon(GooString *new_icon) {
   "19.5 12.5 m S\n"
 
 void AnnotText::draw(Gfx *gfx, GBool printing) {
-  Object obj;
   double ca = 1;
 
   if (!isVisible (printing))
@@ -2583,22 +2475,20 @@ void AnnotText::draw(Gfx *gfx, GBool printing) {
     double bbox[4];
     appearBBox->getBBoxRect(bbox);
     if (ca == 1) {
-      createForm(bbox, gFalse, NULL, &appearance);
+      appearance = createForm(bbox, gFalse, nullptr);
     } else {
-      Object aStream, resDict;
-
-      createForm(bbox, gTrue, NULL, &aStream);
+      Object aStream = createForm(bbox, gTrue, nullptr);
       delete appearBuf;
 
       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-      createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-      createForm(bbox, gFalse, &resDict, &appearance);
+      Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+      appearance = createForm(bbox, gFalse, resDict);
     }
     delete appearBuf;
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
@@ -2608,7 +2498,6 @@ void AnnotText::draw(Gfx *gfx, GBool printing) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   }
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -2619,7 +2508,7 @@ AnnotLink::AnnotLink(PDFDoc *docA, PDFRectangle *rect) :
   Object obj1;
 
   type = typeLink;
-  annotObj.dictSet ("Subtype", obj1.initName ("Link"));
+  annotObj.dictSet ("Subtype", Object(objName, "Link"));
   initialize (docA, annotObj.getDict());
 }
 
@@ -2646,18 +2535,19 @@ void AnnotLink::initialize(PDFDoc *docA, Dict *dict) {
   action = NULL;
 
   // look for destination
-  if (!dict->lookup("Dest", &obj1)->isNull()) {
+  obj1 = dict->lookup("Dest");
+  if (!obj1.isNull()) {
     action = LinkAction::parseDest(&obj1);
   // look for action
   } else {
-    obj1.free();
-    if (dict->lookup("A", &obj1)->isDict()) {
+    obj1 = dict->lookup("A");
+    if (obj1.isDict()) {
       action = LinkAction::parseAction(&obj1, doc->getCatalog()->getBaseURI());
     }
   }
-  obj1.free();
 
-  if (dict->lookup("H", &obj1)->isName()) {
+  obj1 = dict->lookup("H");
+  if (obj1.isName()) {
     const char *effect = obj1.getName();
 
     if (!strcmp(effect, "N")) {
@@ -2674,43 +2564,40 @@ void AnnotLink::initialize(PDFDoc *docA, Dict *dict) {
   } else {
     linkEffect = effectInvert;
   }
-  obj1.free();
   /*
-  if (dict->lookup("PA", &obj1)->isDict()) {
+  obj1 = dict->lookup("PA");
+  if (obj1.isDict()) {
     uriAction = NULL;
   } else {
     uriAction = NULL;
   }
   obj1.free();
   */
-  if (dict->lookup("QuadPoints", &obj1)->isArray()) {
+  obj1 = dict->lookup("QuadPoints");
+  if (obj1.isArray()) {
     quadrilaterals = new AnnotQuadrilaterals(obj1.getArray(), rect);
   } else {
     quadrilaterals = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("BS", &obj1)->isDict()) {
+  obj1 = dict->lookup("BS");
+  if (obj1.isDict()) {
     delete border;
     border = new AnnotBorderBS(obj1.getDict());
   } else if (!border) {
     border = new AnnotBorderBS();
   }
-  obj1.free();
 }
 
 void AnnotLink::draw(Gfx *gfx, GBool printing) {
-  Object obj;
-
   if (!isVisible (printing))
     return;
 
   annotLocker();
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   gfx->drawAnnot(&obj, border, color,
 		 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -2722,11 +2609,8 @@ AnnotFreeText::AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, GooString *da) :
 
   type = typeFreeText;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("FreeText"));
-
-  Object obj2;
-  obj2.initString (da->copy());
-  annotObj.dictSet("DA", &obj2);
+  annotObj.dictSet ("Subtype", Object(objName, "FreeText"));
+  annotObj.dictSet("DA", Object(da->copy()));
 
   initialize (docA, annotObj.getDict());
 }
@@ -2756,48 +2640,43 @@ AnnotFreeText::~AnnotFreeText() {
 void AnnotFreeText::initialize(PDFDoc *docA, Dict *dict) {
   Object obj1;
 
-  if (dict->lookup("DA", &obj1)->isString()) {
+  obj1 = dict->lookup("DA");
+  if (obj1.isString()) {
     appearanceString = obj1.getString()->copy();
   } else {
     appearanceString = new GooString();
     error(errSyntaxError, -1, "Bad appearance for annotation");
     ok = gFalse;
   }
-  obj1.free();
 
-  if (dict->lookup("Q", &obj1)->isInt()) {
+  obj1 = dict->lookup("Q");
+  if (obj1.isInt()) {
     quadding = (AnnotFreeTextQuadding) obj1.getInt();
   } else {
     quadding = quaddingLeftJustified;
   }
-  obj1.free();
 
-  if (dict->lookup("DS", &obj1)->isString()) {
+  obj1 = dict->lookup("DS");
+  if (obj1.isString()) {
     styleString = obj1.getString()->copy();
   } else {
     styleString = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("CL", &obj1)->isArray() && obj1.arrayGetLength() >= 4) {
+  obj1 = dict->lookup("CL");
+  if (obj1.isArray() && obj1.arrayGetLength() >= 4) {
     double x1, y1, x2, y2;
     Object obj2;
 
-    (obj1.arrayGet(0, &obj2)->isNum() ? x1 = obj2.getNum() : x1 = 0);
-    obj2.free();
-    (obj1.arrayGet(1, &obj2)->isNum() ? y1 = obj2.getNum() : y1 = 0);
-    obj2.free();
-    (obj1.arrayGet(2, &obj2)->isNum() ? x2 = obj2.getNum() : x2 = 0);
-    obj2.free();
-    (obj1.arrayGet(3, &obj2)->isNum() ? y2 = obj2.getNum() : y2 = 0);
-    obj2.free();
+    (obj2 = obj1.arrayGet(0), obj2.isNum() ? x1 = obj2.getNum() : x1 = 0);
+    (obj2 = obj1.arrayGet(1), obj2.isNum() ? y1 = obj2.getNum() : y1 = 0);
+    (obj2 = obj1.arrayGet(2), obj2.isNum() ? x2 = obj2.getNum() : x2 = 0);
+    (obj2 = obj1.arrayGet(3), obj2.isNum() ? y2 = obj2.getNum() : y2 = 0);
 
     if (obj1.arrayGetLength() == 6) {
       double x3, y3;
-      (obj1.arrayGet(4, &obj2)->isNum() ? x3 = obj2.getNum() : x3 = 0);
-      obj2.free();
-      (obj1.arrayGet(5, &obj2)->isNum() ? y3 = obj2.getNum() : y3 = 0);
-      obj2.free();
+      (obj2 = obj1.arrayGet(4), obj2.isNum() ? x3 = obj2.getNum() : x3 = 0);
+      (obj2 = obj1.arrayGet(5), obj2.isNum() ? y3 = obj2.getNum() : y3 = 0);
       calloutLine = new AnnotCalloutMultiLine(x1, y1, x2, y2, x3, y3);
     } else {
       calloutLine = new AnnotCalloutLine(x1, y1, x2, y2);
@@ -2805,9 +2684,9 @@ void AnnotFreeText::initialize(PDFDoc *docA, Dict *dict) {
   } else {
     calloutLine = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("IT", &obj1)->isName()) {
+  obj1 = dict->lookup("IT");
+  if (obj1.isName()) {
     const char *intentName = obj1.getName();
 
     if (!strcmp(intentName, "FreeText")) {
@@ -2822,37 +2701,36 @@ void AnnotFreeText::initialize(PDFDoc *docA, Dict *dict) {
   } else {
     intent = intentFreeText;
   }
-  obj1.free();
 
-  if (dict->lookup("BS", &obj1)->isDict()) {
+  obj1 = dict->lookup("BS");
+  if (obj1.isDict()) {
     delete border;
     border = new AnnotBorderBS(obj1.getDict());
   } else if (!border) {
     border = new AnnotBorderBS();
   }
-  obj1.free();
 
-  if (dict->lookup("BE", &obj1)->isDict()) {
+  obj1 = dict->lookup("BE");
+  if (obj1.isDict()) {
     borderEffect = new AnnotBorderEffect(obj1.getDict());
   } else {
     borderEffect = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("RD", &obj1)->isArray()) {
+  obj1 = dict->lookup("RD");
+  if (obj1.isArray()) {
     rectangle = parseDiffRectangle(obj1.getArray(), rect);
   } else {
     rectangle = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("LE", &obj1)->isName()) {
+  obj1 = dict->lookup("LE");
+  if (obj1.isName()) {
     GooString styleName(obj1.getName());
     endStyle = parseAnnotLineEndingStyle(&styleName);
   } else {
     endStyle = annotLineEndingNone;
   }
-  obj1.free();
 }
 
 void AnnotFreeText::setContents(GooString *new_content) {
@@ -2869,17 +2747,14 @@ void AnnotFreeText::setAppearanceString(GooString *new_string) {
     appearanceString = new GooString();
   }
 
-  Object obj1;
-  obj1.initString(appearanceString->copy());
-  update ("DA", &obj1);
+  update ("DA", Object(appearanceString->copy()));
   invalidateAppearance();
 }
 
 void AnnotFreeText::setQuadding(AnnotFreeTextQuadding new_quadding) {
   Object obj1;
   quadding = new_quadding;
-  obj1.initInt((int)quadding);
-  update ("Q", &obj1);
+  update ("Q", Object((int)quadding));
   invalidateAppearance();
 }
 
@@ -2897,9 +2772,7 @@ void AnnotFreeText::setStyleString(GooString *new_string) {
     styleString = new GooString();
   }
 
-  Object obj1;
-  obj1.initString(styleString->copy());
-  update ("DS", &obj1);
+  update ("DS", Object(styleString->copy()));
 }
 
 void AnnotFreeText::setCalloutLine(AnnotCalloutLine *line) {
@@ -2907,73 +2780,58 @@ void AnnotFreeText::setCalloutLine(AnnotCalloutLine *line) {
 
   Object obj1;
   if (line == NULL) {
-    obj1.initNull();
+    obj1.setToNull();
     calloutLine = NULL;
   } else {
     double x1 = line->getX1(), y1 = line->getY1();
     double x2 = line->getX2(), y2 = line->getY2();
-    Object obj2;
-    obj1.initArray(xref);
-    obj1.arrayAdd( obj2.initReal(x1) );
-    obj1.arrayAdd( obj2.initReal(y1) );
-    obj1.arrayAdd( obj2.initReal(x2) );
-    obj1.arrayAdd( obj2.initReal(y2) );
+    obj1 = Object( new Array(xref) );
+    obj1.arrayAdd( Object(x1) );
+    obj1.arrayAdd( Object(y1) );
+    obj1.arrayAdd( Object(x2) );
+    obj1.arrayAdd( Object(y2) );
 
     AnnotCalloutMultiLine *mline = dynamic_cast<AnnotCalloutMultiLine*>(line);
     if (mline) {
       double x3 = mline->getX3(), y3 = mline->getY3();
-      obj1.arrayAdd( obj2.initReal(x3) );
-      obj1.arrayAdd( obj2.initReal(y3) );
+      obj1.arrayAdd( Object(x3) );
+      obj1.arrayAdd( Object(y3) );
       calloutLine = new AnnotCalloutMultiLine(x1, y1, x2, y2, x3, y3);
     } else {
       calloutLine = new AnnotCalloutLine(x1, y1, x2, y2);
     }
   }
 
-  update("CL", &obj1);
+  update("CL", std::move(obj1));
   invalidateAppearance();
 }
 
 void AnnotFreeText::setIntent(AnnotFreeTextIntent new_intent) {
-  Object obj1;
+  const char *intentName;
 
   intent = new_intent;
   if (new_intent == intentFreeText)
-    obj1.initName("FreeText");
+    intentName = "FreeText";
   else if (new_intent == intentFreeTextCallout)
-    obj1.initName("FreeTextCallout");
+    intentName = "FreeTextCallout";
   else // intentFreeTextTypeWriter
-    obj1.initName("FreeTextTypeWriter");
-  update ("IT", &obj1);
+    intentName = "FreeTextTypeWriter";
+  update ("IT", Object(objName, intentName));
 }
 
-static GfxFont * createAnnotDrawFont(XRef * xref, Object *fontResDict)
+static GfxFont * createAnnotDrawFont(XRef * xref, Dict *fontResDict)
 {
-  Ref dummyRef = { -1, -1 };
-
-  Object baseFontObj, subtypeObj, encodingObj;
-  baseFontObj.initName("Helvetica");
-  subtypeObj.initName("Type0");
-  encodingObj.initName("WinAnsiEncoding");
+  const Ref dummyRef = { -1, -1 };
 
-  Object fontDictObj;
   Dict *fontDict = new Dict(xref);
-  fontDict->decRef();
-  fontDict->add(copyString("BaseFont"), &baseFontObj);
-  fontDict->add(copyString("Subtype"), &subtypeObj);
-  fontDict->add(copyString("Encoding"), &encodingObj);
-  fontDictObj.initDict(fontDict);
+  fontDict->add(copyString("BaseFont"), Object(objName, "Helvetica"));
+  fontDict->add(copyString("Subtype"), Object(objName, "Type0"));
+  fontDict->add(copyString("Encoding"), Object(objName, "WinAnsiEncoding"));
 
-  Object fontsDictObj;
   Dict *fontsDict = new Dict(xref);
-  fontsDict->decRef();
-  fontsDict->add(copyString("AnnotDrawFont"), &fontDictObj);
-  fontsDictObj.initDict(fontsDict);
+  fontsDict->add(copyString("AnnotDrawFont"), Object(fontDict));
 
-  Dict *dict = new Dict(xref);
-  dict->decRef();
-  dict->add(copyString("Font"), &fontsDictObj);
-  fontResDict->initDict(dict);
+  fontResDict->add(copyString("Font"), Object(fontsDict));
 
   return GfxFont::makeFont(xref, "AnnotDrawFont", dummyRef, fontDict);
 }
@@ -3073,8 +2931,8 @@ void AnnotFreeText::generateFreeTextAppearance()
   const double textwidth = width - 2*textmargin;
   appearBuf->appendf ("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re W n\n", textmargin, textwidth, height - 2*textmargin);
 
-  Object fontResDict;
-  GfxFont *font = createAnnotDrawFont(xref, &fontResDict);
+  Dict *fontResDict = new Dict(xref);
+  GfxFont *font = createAnnotDrawFont(xref, fontResDict);
 
   // Set font state
   setColor(fontcolor, gTrue);
@@ -3115,23 +2973,19 @@ void AnnotFreeText::generateFreeTextAppearance()
   bbox[3] = rect->y2 - rect->y1;
 
   if (ca == 1) {
-    createForm(bbox, gFalse, &fontResDict, &appearance);
+    appearance = createForm(bbox, gFalse, fontResDict);
   } else {
-    Object aStream, resDict;
-
-    createForm(bbox, gTrue, &fontResDict, &aStream);
+    Object aStream = createForm(bbox, gTrue, fontResDict);
     delete appearBuf;
 
     appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-    createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-    createForm(bbox, gFalse, &resDict, &appearance);
+    Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+    appearance = createForm(bbox, gFalse, resDict);
   }
   delete appearBuf;
 }
 
 void AnnotFreeText::draw(Gfx *gfx, GBool printing) {
-  Object obj;
-
   if (!isVisible (printing))
     return;
 
@@ -3141,19 +2995,18 @@ void AnnotFreeText::draw(Gfx *gfx, GBool printing) {
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                  rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
-  obj.free();
 }
 
 // Before retrieving the res dict, regenerate the appearance stream if needed,
 // because AnnotFreeText::draw needs to store font info in the res dict
-Object *AnnotFreeText::getAppearanceResDict(Object *dest) {
+Object AnnotFreeText::getAppearanceResDict() {
   if (appearance.isNull()) {
     generateFreeTextAppearance();
   }
-  return Annot::getAppearanceResDict(dest);
+  return Annot::getAppearanceResDict();
 }
 
 //------------------------------------------------------------------------
@@ -3165,7 +3018,7 @@ AnnotLine::AnnotLine(PDFDoc *docA, PDFRectangle *rect) :
   Object obj1;
 
   type = typeLine;
-  annotObj.dictSet ("Subtype", obj1.initName ("Line"));
+  annotObj.dictSet ("Subtype", Object(objName, "Line"));
 
   initialize (docA, annotObj.getDict());
 }
@@ -3190,18 +3043,15 @@ AnnotLine::~AnnotLine() {
 void AnnotLine::initialize(PDFDoc *docA, Dict *dict) {
   Object obj1;
 
-  if (dict->lookup("L", &obj1)->isArray() && obj1.arrayGetLength() == 4) {
+  obj1 = dict->lookup("L");
+  if (obj1.isArray() && obj1.arrayGetLength() == 4) {
     Object obj2;
     double x1, y1, x2, y2;
 
-    (obj1.arrayGet(0, &obj2)->isNum() ? x1 = obj2.getNum() : x1 = 0);
-    obj2.free();
-    (obj1.arrayGet(1, &obj2)->isNum() ? y1 = obj2.getNum() : y1 = 0);
-    obj2.free();
-    (obj1.arrayGet(2, &obj2)->isNum() ? x2 = obj2.getNum() : x2 = 0);
-    obj2.free();
-    (obj1.arrayGet(3, &obj2)->isNum() ? y2 = obj2.getNum() : y2 = 0);
-    obj2.free();
+    (obj2 = obj1.arrayGet(0), obj2.isNum() ? x1 = obj2.getNum() : x1 = 0);
+    (obj2 = obj1.arrayGet(1), obj2.isNum() ? y1 = obj2.getNum() : y1 = 0);
+    (obj2 = obj1.arrayGet(2), obj2.isNum() ? x2 = obj2.getNum() : x2 = 0);
+    (obj2 = obj1.arrayGet(3), obj2.isNum() ? y2 = obj2.getNum() : y2 = 0);
 
     coord1 = new AnnotCoord(x1, y1);
     coord2 = new AnnotCoord(x2, y2);
@@ -3209,43 +3059,43 @@ void AnnotLine::initialize(PDFDoc *docA, Dict *dict) {
     coord1 = new AnnotCoord();
     coord2 = new AnnotCoord();
   }
-  obj1.free();
 
-  if (dict->lookup("LE", &obj1)->isArray() && obj1.arrayGetLength() == 2) {
+  obj1 = dict->lookup("LE");
+  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
     Object obj2;
 
-    if(obj1.arrayGet(0, &obj2)->isString())
+    obj2 = obj1.arrayGet(0);
+    if (obj2.isString())
       startStyle = parseAnnotLineEndingStyle(obj2.getString());
     else
       startStyle = annotLineEndingNone;
-    obj2.free();
 
-    if(obj1.arrayGet(1, &obj2)->isString())
+    obj2 = obj1.arrayGet(1);
+    if (obj2.isString())
       endStyle = parseAnnotLineEndingStyle(obj2.getString());
     else
       endStyle = annotLineEndingNone;
-    obj2.free();
 
   } else {
     startStyle = endStyle = annotLineEndingNone;
   }
-  obj1.free();
 
-  if (dict->lookup("IC", &obj1)->isArray()) {
+  obj1 = dict->lookup("IC");
+  if (obj1.isArray()) {
     interiorColor = new AnnotColor(obj1.getArray());
   } else {
     interiorColor = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("LL", &obj1)->isNum()) {
+  obj1 = dict->lookup("LL");
+  if (obj1.isNum()) {
     leaderLineLength = obj1.getNum();
   } else {
     leaderLineLength = 0;
   }
-  obj1.free();
 
-  if (dict->lookup("LLE", &obj1)->isNum()) {
+  obj1 = dict->lookup("LLE");
+  if (obj1.isNum()) {
     leaderLineExtension = obj1.getNum();
 
     if (leaderLineExtension < 0)
@@ -3253,16 +3103,16 @@ void AnnotLine::initialize(PDFDoc *docA, Dict *dict) {
   } else {
     leaderLineExtension = 0;
   }
-  obj1.free();
 
-  if (dict->lookup("Cap", &obj1)->isBool()) {
+  obj1 = dict->lookup("Cap");
+  if (obj1.isBool()) {
     caption = obj1.getBool();
   } else {
     caption = gFalse;
   }
-  obj1.free();
 
-  if (dict->lookup("IT", &obj1)->isName()) {
+  obj1 = dict->lookup("IT");
+  if (obj1.isName()) {
     const char *intentName = obj1.getName();
 
     if(!strcmp(intentName, "LineArrow")) {
@@ -3275,9 +3125,9 @@ void AnnotLine::initialize(PDFDoc *docA, Dict *dict) {
   } else {
     intent = intentLineArrow;
   }
-  obj1.free();
 
-  if (dict->lookup("LLO", &obj1)->isNum()) {
+  obj1 = dict->lookup("LLO");
+  if (obj1.isNum()) {
     leaderLineOffset = obj1.getNum();
 
     if (leaderLineOffset < 0)
@@ -3285,9 +3135,9 @@ void AnnotLine::initialize(PDFDoc *docA, Dict *dict) {
   } else {
     leaderLineOffset = 0;
   }
-  obj1.free();
 
-  if (dict->lookup("CP", &obj1)->isName()) {
+  obj1 = dict->lookup("CP");
+  if (obj1.isName()) {
     const char *captionName = obj1.getName();
 
     if(!strcmp(captionName, "Inline")) {
@@ -3300,36 +3150,33 @@ void AnnotLine::initialize(PDFDoc *docA, Dict *dict) {
   } else {
     captionPos = captionPosInline;
   }
-  obj1.free();
 
-  if (dict->lookup("Measure", &obj1)->isDict()) {
+  obj1 = dict->lookup("Measure");
+  if (obj1.isDict()) {
     measure = NULL;
   } else {
     measure = NULL;
   }
-  obj1.free();
 
-  if ((dict->lookup("CO", &obj1)->isArray()) && (obj1.arrayGetLength() == 2)) {
+  obj1 = dict->lookup("CO");
+  if (obj1.isArray() && (obj1.arrayGetLength() == 2)) {
     Object obj2;
 
-    (obj1.arrayGet(0, &obj2)->isNum() ? captionTextHorizontal = obj2.getNum() :
-      captionTextHorizontal = 0);
-    obj2.free();
-    (obj1.arrayGet(1, &obj2)->isNum() ? captionTextVertical = obj2.getNum() :
-      captionTextVertical = 0);
-    obj2.free();
+    obj2 = obj1.arrayGet(0);
+    captionTextHorizontal = obj2.isNum() ? obj2.getNum() : 0;
+    obj2 = obj1.arrayGet(1);
+    captionTextVertical = obj2.isNum() ? obj2.getNum() : 0;
   } else {
     captionTextHorizontal = captionTextVertical = 0;
   }
-  obj1.free();
 
-  if (dict->lookup("BS", &obj1)->isDict()) {
+  obj1 = dict->lookup("BS");
+  if (obj1.isDict()) {
     delete border;
     border = new AnnotBorderBS(obj1.getDict());
   } else if (!border) {
     border = new AnnotBorderBS();
   }
-  obj1.free();
 }
 
 void AnnotLine::setContents(GooString *new_content) {
@@ -3339,34 +3186,30 @@ void AnnotLine::setContents(GooString *new_content) {
 }
 
 void AnnotLine::setVertices(double x1, double y1, double x2, double y2) {
-  Object obj1, obj2;
-
   delete coord1;
   coord1 = new AnnotCoord(x1, y1);
   delete coord2;
   coord2 = new AnnotCoord(x2, y2);
 
-  obj1.initArray(xref);
-  obj1.arrayAdd( obj2.initReal(x1) );
-  obj1.arrayAdd( obj2.initReal(y1) );
-  obj1.arrayAdd( obj2.initReal(x2) );
-  obj1.arrayAdd( obj2.initReal(y2) );
+  Array *lArray = new Array(xref);
+  lArray->add( Object(x1) );
+  lArray->add( Object(y1) );
+  lArray->add( Object(x2) );
+  lArray->add( Object(y2) );
 
-  update("L", &obj1);
+  update("L", Object(lArray));
   invalidateAppearance();
 }
 
 void AnnotLine::setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end) {
-  Object obj1, obj2;
-
   startStyle = start;
   endStyle = end;
 
-  obj1.initArray(xref);
-  obj1.arrayAdd( obj2.initName(convertAnnotLineEndingStyle( startStyle )) );
-  obj1.arrayAdd( obj2.initName(convertAnnotLineEndingStyle( endStyle )) );
+  Array *leArray = new Array(xref);
+  leArray->add( Object(objName, convertAnnotLineEndingStyle( startStyle )) );
+  leArray->add( Object(objName, convertAnnotLineEndingStyle( endStyle )) );
 
-  update("LE", &obj1);
+  update("LE", Object(leArray));
   invalidateAppearance();
 }
 
@@ -3374,9 +3217,8 @@ void AnnotLine::setInteriorColor(AnnotColor *new_color) {
   delete interiorColor;
 
   if (new_color) {
-    Object obj1;
-    new_color->writeToObject(xref, &obj1);
-    update ("IC", &obj1);
+    Object obj1 = new_color->writeToObject(xref);
+    update ("IC", std::move(obj1));
     interiorColor = new_color;
   } else {
     interiorColor = NULL;
@@ -3385,45 +3227,35 @@ void AnnotLine::setInteriorColor(AnnotColor *new_color) {
 }
 
 void AnnotLine::setLeaderLineLength(double len) {
-  Object obj1;
-
   leaderLineLength = len;
-  obj1.initReal(len);
-  update ("LL", &obj1);
+  update ("LL", Object(len));
   invalidateAppearance();
 }
 
 void AnnotLine::setLeaderLineExtension(double len) {
-  Object obj1;
-
   leaderLineExtension = len;
-  obj1.initReal(len);
-  update ("LLE", &obj1);
+  update ("LLE", Object(len));
 
   // LL is required if LLE is present
-  obj1.initReal(leaderLineLength);
-  update ("LL", &obj1);
+  update ("LL", Object(leaderLineLength));
   invalidateAppearance();
 }
 
 void AnnotLine::setCaption(bool new_cap) {
-  Object obj1;
-
   caption = new_cap;
-  obj1.initBool(new_cap);
-  update ("Cap", &obj1);
+  update ("Cap", Object(new_cap));
   invalidateAppearance();
 }
 
 void AnnotLine::setIntent(AnnotLineIntent new_intent) {
-  Object obj1;
+  const char *intentName;
 
   intent = new_intent;
   if (new_intent == intentLineArrow)
-    obj1.initName("LineArrow");
+    intentName = "LineArrow";
   else // intentLineDimension
-    obj1.initName("LineDimension");
-  update ("IT", &obj1);
+    intentName = "LineDimension";
+  update ("IT", Object(objName, intentName));
 }
 
 void AnnotLine::generateLineAppearance()
@@ -3464,12 +3296,13 @@ void AnnotLine::generateLineAppearance()
   const double captionhmargin = 2; // Left and right margin (inline caption only)
   const double captionmaxwidth = main_len - 2 * captionhmargin;
 
-  Object fontResDict;
+  Dict *fontResDict;
   GfxFont *font;
 
   // Calculate caption width and height
   if (caption) {
-    font = createAnnotDrawFont(xref, &fontResDict);
+    fontResDict = new Dict(xref);
+    font = createAnnotDrawFont(xref, fontResDict);
     int lines = 0;
     int i = 0;
     while (i < contents->getLength()) {
@@ -3488,7 +3321,7 @@ void AnnotLine::generateLineAppearance()
       actualCaptionPos = captionPosTop;
     }
   } else {
-    fontResDict.initNull();
+    fontResDict = nullptr;
     font = NULL;
   }
 
@@ -3580,23 +3413,19 @@ void AnnotLine::generateLineAppearance()
   double bbox[4];
   appearBBox->getBBoxRect(bbox);
   if (ca == 1) {
-    createForm(bbox, gFalse, &fontResDict, &appearance);
+    appearance = createForm(bbox, gFalse, fontResDict);
   } else {
-    Object aStream, resDict;
-
-    createForm(bbox, gTrue, &fontResDict, &aStream);
+    Object aStream = createForm(bbox, gTrue, fontResDict);
     delete appearBuf;
 
     appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-    createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-    createForm(bbox, gFalse, &resDict, &appearance);
+    Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+    appearance = createForm(bbox, gFalse, resDict);
   }
   delete appearBuf;
 }
 
 void AnnotLine::draw(Gfx *gfx, GBool printing) {
-  Object obj;
-
   if (!isVisible (printing))
     return;
 
@@ -3606,7 +3435,7 @@ void AnnotLine::draw(Gfx *gfx, GBool printing) {
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
@@ -3616,16 +3445,15 @@ void AnnotLine::draw(Gfx *gfx, GBool printing) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   }
-  obj.free();
 }
 
 // Before retrieving the res dict, regenerate the appearance stream if needed,
 // because AnnotLine::draw may need to store font info in the res dict
-Object *AnnotLine::getAppearanceResDict(Object *dest) {
+Object AnnotLine::getAppearanceResDict() {
   if (appearance.isNull()) {
     generateLineAppearance();
   }
-  return Annot::getAppearanceResDict(dest);
+  return Annot::getAppearanceResDict();
 }
 
 //------------------------------------------------------------------------
@@ -3637,28 +3465,27 @@ AnnotTextMarkup::AnnotTextMarkup(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype
 
   switch (subType) {
     case typeHighlight:
-      annotObj.dictSet ("Subtype", obj1.initName ("Highlight"));
+      annotObj.dictSet ("Subtype", Object(objName, "Highlight"));
       break;
     case typeUnderline:
-      annotObj.dictSet ("Subtype", obj1.initName ("Underline"));
+      annotObj.dictSet ("Subtype", Object(objName, "Underline"));
       break;
     case typeSquiggly:
-      annotObj.dictSet ("Subtype", obj1.initName ("Squiggly"));
+      annotObj.dictSet ("Subtype", Object(objName, "Squiggly"));
       break;
     case typeStrikeOut:
-      annotObj.dictSet ("Subtype", obj1.initName ("StrikeOut"));
+      annotObj.dictSet ("Subtype", Object(objName, "StrikeOut"));
       break;
     default:
       assert (0 && "Invalid subtype for AnnotTextMarkup\n");
   }
 
   // Store dummy quadrilateral with null coordinates
-  Object obj2, obj3;
-  obj2.initArray (doc->getXRef());
+  Array *quadPoints = new Array(doc->getXRef());
   for (int i = 0; i < 4*2; ++i) {
-    obj2.arrayAdd (obj3.initReal (0));
+    quadPoints->add(Object(0.));
   }
-  annotObj.dictSet ("QuadPoints", &obj2);
+  annotObj.dictSet ("QuadPoints", Object(quadPoints));
 
   initialize(docA, annotObj.getDict());
 }
@@ -3673,7 +3500,8 @@ AnnotTextMarkup::AnnotTextMarkup(PDFDoc *docA, Dict *dict, Object *obj) :
 void AnnotTextMarkup::initialize(PDFDoc *docA, Dict *dict) {
   Object obj1;
 
-  if (dict->lookup("Subtype", &obj1)->isName()) {
+  obj1 = dict->lookup("Subtype");
+  if (obj1.isName()) {
     GooString typeName(obj1.getName());
     if (!typeName.cmp("Highlight")) {
       type = typeHighlight;
@@ -3685,76 +3513,70 @@ void AnnotTextMarkup::initialize(PDFDoc *docA, Dict *dict) {
       type = typeStrikeOut;
     }
   }
-  obj1.free();
 
-  if(dict->lookup("QuadPoints", &obj1)->isArray()) {
+  obj1 = dict->lookup("QuadPoints");
+  if (obj1.isArray()) {
     quadrilaterals = new AnnotQuadrilaterals(obj1.getArray(), rect);
   } else {
     error(errSyntaxError, -1, "Bad Annot Text Markup QuadPoints");
     quadrilaterals = NULL;
     ok = gFalse;
   }
-  obj1.free();
 }
 
 AnnotTextMarkup::~AnnotTextMarkup() {
-  if(quadrilaterals) {
-    delete quadrilaterals;
-  }
+  delete quadrilaterals;
 }
 
 void AnnotTextMarkup::setType(AnnotSubtype new_type) {
-  Object obj1;
+  const char *typeName;
 
   switch (new_type) {
     case typeHighlight:
-      obj1.initName("Highlight");
+      typeName = "Highlight";
       break;
     case typeUnderline:
-      obj1.initName("Underline");
+      typeName = "Underline";
       break;
     case typeSquiggly:
-      obj1.initName("Squiggly");
+      typeName = "Squiggly";
       break;
     case typeStrikeOut:
-      obj1.initName("StrikeOut");
+      typeName = "StrikeOut";
       break;
     default:
       assert(!"Invalid subtype");
   }
 
   type = new_type;
-  update("Subtype", &obj1);
+  update("Subtype", Object(objName, typeName));
   invalidateAppearance();
 }
 
 void AnnotTextMarkup::setQuadrilaterals(AnnotQuadrilaterals *quadPoints) {
-  Object obj1, obj2;
-  obj1.initArray (xref);
+  Array *a = new Array(xref);
 
   for (int i = 0; i < quadPoints->getQuadrilateralsLength(); ++i) {
-    obj1.arrayAdd (obj2.initReal (quadPoints->getX1(i)));
-    obj1.arrayAdd (obj2.initReal (quadPoints->getY1(i)));
-    obj1.arrayAdd (obj2.initReal (quadPoints->getX2(i)));
-    obj1.arrayAdd (obj2.initReal (quadPoints->getY2(i)));
-    obj1.arrayAdd (obj2.initReal (quadPoints->getX3(i)));
-    obj1.arrayAdd (obj2.initReal (quadPoints->getY3(i)));
-    obj1.arrayAdd (obj2.initReal (quadPoints->getX4(i)));
-    obj1.arrayAdd (obj2.initReal (quadPoints->getY4(i)));
+    a->add(Object(quadPoints->getX1(i)));
+    a->add(Object(quadPoints->getY1(i)));
+    a->add(Object(quadPoints->getX2(i)));
+    a->add(Object(quadPoints->getY2(i)));
+    a->add(Object(quadPoints->getX3(i)));
+    a->add(Object(quadPoints->getY3(i)));
+    a->add(Object(quadPoints->getX4(i)));
+    a->add(Object(quadPoints->getY4(i)));
   }
 
   delete quadrilaterals;
-  quadrilaterals = new AnnotQuadrilaterals(obj1.getArray(), rect);
+  quadrilaterals = new AnnotQuadrilaterals(a, rect);
 
-  annotObj.dictSet ("QuadPoints", &obj1);
+  annotObj.dictSet ("QuadPoints", Object(a));
   invalidateAppearance();
 }
 
 void AnnotTextMarkup::draw(Gfx *gfx, GBool printing) {
-  Object obj;
   double ca = 1;
   int i;
-  Object obj1, obj2;
 
   if (!isVisible (printing))
     return;
@@ -3851,8 +3673,6 @@ void AnnotTextMarkup::draw(Gfx *gfx, GBool printing) {
       break;
     default:
     case typeHighlight:
-      appearance.free();
-
       if (color)
         setColor(color, gTrue);
 
@@ -3888,32 +3708,32 @@ void AnnotTextMarkup::draw(Gfx *gfx, GBool printing) {
     }
     appearBuf->append ("Q\n");
 
-    Object aStream, resDict;
+    Object aStream;
     double bbox[4];
     bbox[0] = appearBBox->getPageXMin();
     bbox[1] = appearBBox->getPageYMin();
     bbox[2] = appearBBox->getPageXMax();
     bbox[3] = appearBBox->getPageYMax();
-    createForm(bbox, gTrue, NULL, &aStream);
+    aStream = createForm(bbox, gTrue, NULL);
     delete appearBuf;
 
     appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-    createResourcesDict("Fm0", &aStream, "GS0", 1, blendMultiply ? "Multiply" : NULL, &resDict);
+    Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", 1, blendMultiply ? "Multiply" : NULL);
     if (ca == 1) {
-      createForm(bbox, gFalse, &resDict, &appearance);
+      appearance = createForm(bbox, gFalse, resDict);
     } else {
-      createForm(bbox, gTrue, &resDict, &aStream);
+      aStream = createForm(bbox, gTrue, resDict);
       delete appearBuf;
 
       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-      createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-      createForm(bbox, gFalse, &resDict, &appearance);
+      Dict *resDict2 = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+      appearance = createForm(bbox, gFalse, resDict2);
     }
     delete appearBuf;
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
@@ -3923,7 +3743,6 @@ void AnnotTextMarkup::draw(Gfx *gfx, GBool printing) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   }
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -3951,8 +3770,6 @@ AnnotWidget::~AnnotWidget() {
   if (action)
     delete action;
 
-  additionalActions.free();
-
   if (parent)
     delete parent;
 }
@@ -3962,7 +3779,8 @@ void AnnotWidget::initialize(PDFDoc *docA, Dict *dict) {
 
   form = doc->getCatalog()->getForm();
 
-  if(dict->lookup("H", &obj1)->isName()) {
+  obj1 = dict->lookup("H");
+  if (obj1.isName()) {
     const char *modeName = obj1.getName();
 
     if(!strcmp(modeName, "N")) {
@@ -3977,35 +3795,34 @@ void AnnotWidget::initialize(PDFDoc *docA, Dict *dict) {
   } else {
     mode = highlightModeInvert;
   }
-  obj1.free();
 
-  if(dict->lookup("MK", &obj1)->isDict()) {
+  obj1 = dict->lookup("MK");
+  if (obj1.isDict()) {
     appearCharacs = new AnnotAppearanceCharacs(obj1.getDict());
   } else {
     appearCharacs = NULL;
   }
-  obj1.free();
 
   action = NULL;
-  if(dict->lookup("A", &obj1)->isDict()) {
+  obj1 = dict->lookup("A");
+  if (obj1.isDict()) {
     action = LinkAction::parseAction(&obj1, doc->getCatalog()->getBaseURI());
   }
-  obj1.free();
 
-  dict->lookupNF("AA", &additionalActions);
+  additionalActions = dict->lookupNF("AA");
 
-  if(dict->lookup("Parent", &obj1)->isDict()) {
+  obj1 = dict->lookup("Parent");
+  if (obj1.isDict()) {
     parent = NULL;
   } else {
     parent = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("BS", &obj1)->isDict()) {
+  obj1 = dict->lookup("BS");
+  if (obj1.isDict()) {
     delete border;
     border = new AnnotBorderBS(obj1.getDict());
   }
-  obj1.free();
 
   updatedAppearanceStream.num = updatedAppearanceStream.gen = -1;
 }
@@ -5038,9 +4855,7 @@ void AnnotWidget::drawFormFieldChoice(GfxResources *resources, GooString *da) {
 }
 
 void AnnotWidget::generateFieldAppearance() {
-  Object appearDict, obj1, obj2;
   GfxResources *resources;
-  MemStream *appearStream;
   GooString *da;
 
   appearBuf = new GooString ();
@@ -5085,28 +4900,26 @@ void AnnotWidget::generateFieldAppearance() {
   }
 
   // build the appearance stream dictionary
-  appearDict.initDict(xref);
-  appearDict.dictAdd(copyString("Length"),
-      obj1.initInt(appearBuf->getLength()));
-  appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form"));
-  obj1.initArray(xref);
-  obj1.arrayAdd(obj2.initReal(0));
-  obj1.arrayAdd(obj2.initReal(0));
-  obj1.arrayAdd(obj2.initReal(rect->x2 - rect->x1));
-  obj1.arrayAdd(obj2.initReal(rect->y2 - rect->y1));
-  appearDict.dictAdd(copyString("BBox"), &obj1);
+  Dict *appearDict = new Dict(xref);
+  appearDict->add(copyString("Length"), Object(appearBuf->getLength()));
+  appearDict->add(copyString("Subtype"), Object(objName, "Form"));
+  Array *bbox = new Array(xref);
+  bbox->add(Object(0));
+  bbox->add(Object(0));
+  bbox->add(Object(rect->x2 - rect->x1));
+  bbox->add(Object(rect->y2 - rect->y1));
+  appearDict->add(copyString("BBox"), Object(bbox));
 
   // set the resource dictionary
   Object *resDict = form->getDefaultResourcesObj();
   if (resDict->isDict()) {
-    appearDict.dictAdd(copyString("Resources"), resDict->copy(&obj1));
+    appearDict->add(copyString("Resources"), resDict->copy());
   }
 
   // build the appearance stream
-  appearStream = new MemStream(copyString(appearBuf->getCString()), 0,
-      appearBuf->getLength(), &appearDict);
-  appearance.free();
-  appearance.initStream(appearStream);
+  MemStream *appearStream = new MemStream(copyString(appearBuf->getCString()), 0,
+      appearBuf->getLength(), Object(appearDict));
+  appearance = Object(static_cast<Stream*>(appearStream));
   delete appearBuf;
 
   appearStream->setNeedFree(gTrue);
@@ -5129,8 +4942,7 @@ void AnnotWidget::updateAppearanceStream()
   generateFieldAppearance();
 
   // Fetch the appearance stream we've just created
-  Object obj1;
-  appearance.fetch(xref, &obj1);
+  Object obj1 = appearance.fetch(xref);
 
   // If this the first time updateAppearanceStream() is called on this widget,
   // create a new AP dictionary containing the new appearance stream.
@@ -5138,26 +4950,22 @@ void AnnotWidget::updateAppearanceStream()
   if (updatedAppearanceStream.num == -1) {
     // Write the appearance stream
     updatedAppearanceStream = xref->addIndirectObject(&obj1);
-    obj1.free();
 
     // Write the AP dictionary
-    Object obj2;
-    obj1.initDict(xref);
-    obj1.dictAdd(copyString("N"), obj2.initRef(updatedAppearanceStream.num, updatedAppearanceStream.gen));
-    update("AP", &obj1);
+    obj1 = Object(new Dict(xref));
+    obj1.dictAdd(copyString("N"), Object(updatedAppearanceStream.num, updatedAppearanceStream.gen));
 
     // Update our internal pointers to the appearance dictionary
     appearStreams = new AnnotAppearance(doc, &obj1);
+
+    update("AP", std::move(obj1));
   } else {
     // Replace the existing appearance stream
     xref->setModifiedObject(&obj1, updatedAppearanceStream);
-    obj1.free();
   }
 }
 
 void AnnotWidget::draw(Gfx *gfx, GBool printing) {
-  Object obj;
-
   if (!isVisible (printing))
     return;
 
@@ -5173,29 +4981,19 @@ void AnnotWidget::draw(Gfx *gfx, GBool printing) {
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   if (addDingbatsResource) {
     // We are forcing ZaDb but the font does not exist
     // so create a fake one
-    Object baseFontObj, subtypeObj;
-    baseFontObj.initName("ZapfDingbats");
-    subtypeObj.initName("Type1");
-
-    Object fontDictObj;
     Dict *fontDict = new Dict(gfx->getXRef());
-    fontDict->decRef();
-    fontDict->add(copyString("BaseFont"), &baseFontObj);
-    fontDict->add(copyString("Subtype"), &subtypeObj);
-    fontDictObj.initDict(fontDict);
+    fontDict->add(copyString("BaseFont"), Object(objName, "ZapfDingbats"));
+    fontDict->add(copyString("Subtype"), Object(objName, "Type1"));
 
-    Object fontsDictObj;
     Dict *fontsDict = new Dict(gfx->getXRef());
-    fontsDict->decRef();
-    fontsDict->add(copyString("ZaDb"), &fontDictObj);
-    fontsDictObj.initDict(fontsDict);
+    fontsDict->add(copyString("ZaDb"), Object(fontDict));
 
     Dict *dict = new Dict(gfx->getXRef());
-    dict->add(copyString("Font"), &fontsDictObj);
+    dict->add(copyString("Font"), Object(fontsDict));
     gfx->pushResources(dict);
     delete dict;
   }
@@ -5204,7 +5002,6 @@ void AnnotWidget::draw(Gfx *gfx, GBool printing) {
   if (addDingbatsResource) {
     gfx->popResources();
   }
-  obj.free();
 }
 
 
@@ -5216,7 +5013,7 @@ AnnotMovie::AnnotMovie(PDFDoc *docA, PDFRectangle *rect, Movie *movieA) :
   Object obj1;
 
   type = typeMovie;
-  annotObj.dictSet ("Subtype", obj1.initName ("Movie"));
+  annotObj.dictSet ("Subtype", Object(objName, "Movie"));
 
   movie = movieA->copy();
   // TODO: create movie dict from movieA
@@ -5239,17 +5036,16 @@ AnnotMovie::~AnnotMovie() {
 void AnnotMovie::initialize(PDFDoc *docA, Dict* dict) {
   Object obj1;
 
-  if (dict->lookup("T", &obj1)->isString()) {
+  obj1 = dict->lookup("T");
+  if (obj1.isString()) {
     title = obj1.getString()->copy();
   } else {
     title = NULL;
   }
-  obj1.free();
 
-  Object movieDict;
-  if (dict->lookup("Movie", &movieDict)->isDict()) {
-    Object obj2;
-    dict->lookup("A", &obj2);
+  Object movieDict = dict->lookup("Movie");
+  if (movieDict.isDict()) {
+    Object obj2 = dict->lookup("A");
     if (obj2.isDict())
       movie = new Movie (&movieDict, &obj2);
     else
@@ -5259,79 +5055,66 @@ void AnnotMovie::initialize(PDFDoc *docA, Dict* dict) {
       movie = NULL;
       ok = gFalse;
     }
-    obj2.free();
   } else {
     error(errSyntaxError, -1, "Bad Annot Movie");
     movie = NULL;
     ok = gFalse;
   }
-  movieDict.free();
 }
 
 void AnnotMovie::draw(Gfx *gfx, GBool printing) {
-  Object obj;
-
   if (!isVisible (printing))
     return;
 
   annotLocker();
   if (appearance.isNull() && movie->getShowPoster()) {
     int width, height;
-    Object poster;
-    movie->getPoster(&poster);
+    Object poster = movie->getPoster();
     movie->getAspect(&width, &height);
 
     if (width != -1 && height != -1 && !poster.isNone()) {
-      MemStream *mStream;
-
       appearBuf = new GooString ();
       appearBuf->append ("q\n");
       appearBuf->appendf ("{0:d} 0 0 {1:d} 0 0 cm\n", width, height);
       appearBuf->append ("/MImg Do\n");
       appearBuf->append ("Q\n");
 
-      Object imgDict;
-      imgDict.initDict(gfx->getXRef());
-      imgDict.dictSet ("MImg", &poster);
-
-      Object resDict;
-      resDict.initDict(gfx->getXRef());
-      resDict.dictSet ("XObject", &imgDict);
-
-      Object formDict, obj1, obj2;
-      formDict.initDict(gfx->getXRef());
-      formDict.dictSet("Length", obj1.initInt(appearBuf->getLength()));
-      formDict.dictSet("Subtype", obj1.initName("Form"));
-      formDict.dictSet("Name", obj1.initName("FRM"));
-      obj1.initArray(gfx->getXRef());
-      obj1.arrayAdd(obj2.initInt(0));
-      obj1.arrayAdd(obj2.initInt(0));
-      obj1.arrayAdd(obj2.initInt(width));
-      obj1.arrayAdd(obj2.initInt(height));
-      formDict.dictSet("BBox", &obj1);
-      obj1.initArray(gfx->getXRef());
-      obj1.arrayAdd(obj2.initInt(1));
-      obj1.arrayAdd(obj2.initInt(0));
-      obj1.arrayAdd(obj2.initInt(0));
-      obj1.arrayAdd(obj2.initInt(1));
-      obj1.arrayAdd(obj2.initInt(-width / 2));
-      obj1.arrayAdd(obj2.initInt(-height / 2));
-      formDict.dictSet("Matrix", &obj1);
-      formDict.dictSet("Resources", &resDict);
-
-      Object aStream;
-      mStream = new MemStream(copyString(appearBuf->getCString()), 0,
-			      appearBuf->getLength(), &formDict);
+      Dict *imgDict = new Dict(gfx->getXRef());
+      imgDict->set("MImg", std::move(poster));
+
+      Dict *resDict = new Dict(gfx->getXRef());
+      resDict->set("XObject", Object(imgDict));
+
+      Dict *formDict = new Dict(gfx->getXRef());
+      formDict->set("Length", Object(appearBuf->getLength()));
+      formDict->set("Subtype", Object(objName, "Form"));
+      formDict->set("Name", Object(objName, "FRM"));
+      Array *bboxArray = new Array(gfx->getXRef());
+      bboxArray->add(Object(0));
+      bboxArray->add(Object(0));
+      bboxArray->add(Object(width));
+      bboxArray->add(Object(height));
+      formDict->set("BBox", Object(bboxArray));
+      Array *matrix = new Array(gfx->getXRef());
+      matrix->add(Object(1));
+      matrix->add(Object(0));
+      matrix->add(Object(0));
+      matrix->add(Object(1));
+      matrix->add(Object(-width / 2));
+      matrix->add(Object(-height / 2));
+      formDict->set("Matrix", Object(matrix));
+      formDict->set("Resources", Object(resDict));
+
+      MemStream *mStream = new MemStream(copyString(appearBuf->getCString()), 0,
+			      appearBuf->getLength(), Object(formDict));
       mStream->setNeedFree(gTrue);
-      aStream.initStream(mStream);
       delete appearBuf;
 
-      Object objDict;
-      objDict.initDict(gfx->getXRef());
-      objDict.dictSet ("FRM", &aStream);
+      Dict *dict = new Dict(gfx->getXRef());
+      dict->set("FRM", Object(static_cast<Stream*>(mStream)));
 
-      resDict.initDict(gfx->getXRef());
-      resDict.dictSet ("XObject", &objDict);
+      Dict *resDict2 = new Dict(gfx->getXRef());
+      resDict2->set("XObject", Object(dict));
 
       appearBuf = new GooString ();
       appearBuf->append ("q\n");
@@ -5347,17 +5130,15 @@ void AnnotMovie::draw(Gfx *gfx, GBool printing) {
       bbox[0] = bbox[1] = 0;
       bbox[2] = width;
       bbox[3] = height;
-      createForm(bbox, gFalse, &resDict, &appearance);
+      appearance = createForm(bbox, gFalse, resDict2);
       delete appearBuf;
     }
-    poster.free();
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
 		 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -5369,7 +5150,7 @@ AnnotScreen::AnnotScreen(PDFDoc *docA, PDFRectangle *rect) :
 
   type = typeScreen;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("Screen"));
+  annotObj.dictSet ("Subtype", Object(objName, "Screen"));
   initialize(docA, annotObj.getDict());
 }
 
@@ -5380,27 +5161,23 @@ AnnotScreen::AnnotScreen(PDFDoc *docA, Dict *dict, Object *obj) :
 }
 
 AnnotScreen::~AnnotScreen() {
-  if (title)
-    delete title;
-  if (appearCharacs)
-    delete appearCharacs;
-  if (action)
-    delete action;
-
-  additionalActions.free();
+  delete title;
+  delete appearCharacs;
+  delete action;
 }
 
 void AnnotScreen::initialize(PDFDoc *docA, Dict* dict) {
   Object obj1;
 
   title = NULL;
-  if (dict->lookup("T", &obj1)->isString()) {
+  obj1 = dict->lookup("T");
+  if (obj1.isString()) {
     title = obj1.getString()->copy();
   }
-  obj1.free();
 
   action = NULL;
-  if (dict->lookup("A", &obj1)->isDict()) {
+  obj1 = dict->lookup("A");
+  if (obj1.isDict()) {
     action = LinkAction::parseAction(&obj1, doc->getCatalog()->getBaseURI());
     if (action->getKind() == actionRendition && page == 0) {
       error (errSyntaxError, -1, "Invalid Rendition action: associated screen annotation without P");
@@ -5409,15 +5186,14 @@ void AnnotScreen::initialize(PDFDoc *docA, Dict* dict) {
       ok = gFalse;
     }
   }
-  obj1.free();
 
-  dict->lookupNF("AA", &additionalActions);
+  additionalActions = dict->lookupNF("AA");
 
   appearCharacs = NULL;
-  if(dict->lookup("MK", &obj1)->isDict()) {
+  obj1 = dict->lookup("MK");
+  if (obj1.isDict()) {
     appearCharacs = new AnnotAppearanceCharacs(obj1.getDict());
   }
-  obj1.free();
 }
 
 LinkAction* AnnotScreen::getAdditionalAction(AdditionalActionsType type)
@@ -5436,7 +5212,7 @@ AnnotStamp::AnnotStamp(PDFDoc *docA, PDFRectangle *rect) :
   Object obj1;
 
   type = typeStamp;
-  annotObj.dictSet ("Subtype", obj1.initName ("Stamp"));
+  annotObj.dictSet ("Subtype", Object(objName, "Stamp"));
   initialize(docA, annotObj.getDict());
 }
 
@@ -5451,14 +5227,12 @@ AnnotStamp::~AnnotStamp() {
 }
 
 void AnnotStamp::initialize(PDFDoc *docA, Dict* dict) {
-  Object obj1;
-
-  if (dict->lookup("Name", &obj1)->isName()) {
+  Object obj1 = dict->lookup("Name");
+  if (obj1.isName()) {
     icon = new GooString(obj1.getName());
   } else {
     icon = new GooString("Draft");
   }
-  obj1.free();
 
 }
 
@@ -5471,9 +5245,7 @@ void AnnotStamp::setIcon(GooString *new_icon) {
     icon = new GooString();
   }
 
-  Object obj1;
-  obj1.initName (icon->getCString());
-  update("Name", &obj1);
+  update("Name", Object(objName, icon->getCString()));
   invalidateAppearance();
 }
 
@@ -5486,10 +5258,10 @@ AnnotGeometry::AnnotGeometry(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subT
 
   switch (subType) {
     case typeSquare:
-      annotObj.dictSet ("Subtype", obj1.initName ("Square"));
+      annotObj.dictSet ("Subtype", Object(objName, "Square"));
       break;
     case typeCircle:
-      annotObj.dictSet ("Subtype", obj1.initName ("Circle"));
+      annotObj.dictSet ("Subtype", Object(objName, "Circle"));
       break;
     default:
       assert (0 && "Invalid subtype for AnnotGeometry\n");
@@ -5514,7 +5286,8 @@ AnnotGeometry::~AnnotGeometry() {
 void AnnotGeometry::initialize(PDFDoc *docA, Dict* dict) {
   Object obj1;
 
-  if (dict->lookup("Subtype", &obj1)->isName()) {
+  obj1 = dict->lookup("Subtype");
+  if (obj1.isName()) {
     GooString typeName(obj1.getName());
     if (!typeName.cmp("Square")) {
       type = typeSquare;
@@ -5522,54 +5295,52 @@ void AnnotGeometry::initialize(PDFDoc *docA, Dict* dict) {
       type = typeCircle;
     }
   }
-  obj1.free();
 
-  if (dict->lookup("IC", &obj1)->isArray()) {
+  obj1 = dict->lookup("IC");
+  if (obj1.isArray()) {
     interiorColor = new AnnotColor(obj1.getArray());
   } else {
     interiorColor = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("BS", &obj1)->isDict()) {
+  obj1 = dict->lookup("BS");
+  if (obj1.isDict()) {
     delete border;
     border = new AnnotBorderBS(obj1.getDict());
   } else if (!border) {
     border = new AnnotBorderBS();
   }
-  obj1.free();
 
-  if (dict->lookup("BE", &obj1)->isDict()) {
+  obj1 = dict->lookup("BE");
+  if (obj1.isDict()) {
     borderEffect = new AnnotBorderEffect(obj1.getDict());
   } else {
     borderEffect = NULL;
   }
-  obj1.free();
 
   geometryRect = NULL;
-  if (dict->lookup("RD", &obj1)->isArray()) {
+  obj1 = dict->lookup("RD");
+  if (obj1.isArray()) {
     geometryRect = parseDiffRectangle(obj1.getArray(), rect);
   }
-  obj1.free();
-
 }
 
 void AnnotGeometry::setType(AnnotSubtype new_type) {
-  Object obj1;
+  const char *typeName;
 
   switch (new_type) {
     case typeSquare:
-      obj1.initName("Square");
+      typeName = "Square";
       break;
     case typeCircle:
-      obj1.initName("Circle");
+      typeName = "Circle";
       break;
     default:
       assert(!"Invalid subtype");
   }
 
   type = new_type;
-  update("Subtype", &obj1);
+  update("Subtype", Object(objName, typeName));
   invalidateAppearance();
 }
 
@@ -5577,9 +5348,8 @@ void AnnotGeometry::setInteriorColor(AnnotColor *new_color) {
   delete interiorColor;
 
   if (new_color) {
-    Object obj1;
-    new_color->writeToObject(xref, &obj1);
-    update ("IC", &obj1);
+    Object obj1 = new_color->writeToObject(xref);
+    update ("IC", std::move(obj1));
     interiorColor = new_color;
   } else {
     interiorColor = NULL;
@@ -5588,7 +5358,6 @@ void AnnotGeometry::setInteriorColor(AnnotColor *new_color) {
 }
 
 void AnnotGeometry::draw(Gfx *gfx, GBool printing) {
-  Object obj;
   double ca = 1;
 
   if (!isVisible (printing))
@@ -5674,26 +5443,22 @@ void AnnotGeometry::draw(Gfx *gfx, GBool printing) {
     bbox[2] = rect->x2 - rect->x1;
     bbox[3] = rect->y2 - rect->y1;
     if (ca == 1) {
-      createForm(bbox, gFalse, NULL, &appearance);
+      appearance = createForm(bbox, gFalse, nullptr);
     } else {
-      Object aStream;
-
-      createForm(bbox, gTrue, NULL, &aStream);
+      Object aStream = createForm(bbox, gTrue, nullptr);
       delete appearBuf;
 
-      Object resDict;
       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-      createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-      createForm(bbox, gFalse, &resDict, &appearance);
+      Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+      appearance = createForm(bbox, gFalse, resDict);
     }
     delete appearBuf;
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
 		 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -5705,21 +5470,20 @@ AnnotPolygon::AnnotPolygon(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subTyp
 
   switch (subType) {
     case typePolygon:
-      annotObj.dictSet ("Subtype", obj1.initName ("Polygon"));
+      annotObj.dictSet ("Subtype", Object(objName, "Polygon"));
       break;
     case typePolyLine:
-      annotObj.dictSet ("Subtype", obj1.initName ("PolyLine"));
+      annotObj.dictSet ("Subtype", Object(objName, "PolyLine"));
       break;
     default:
       assert (0 && "Invalid subtype for AnnotGeometry\n");
   }
 
   // Store dummy path with one null vertex only
-  Object obj2, obj3;
-  obj2.initArray (doc->getXRef());
-  obj2.arrayAdd (obj3.initReal (0));
-  obj2.arrayAdd (obj3.initReal (0));
-  annotObj.dictSet ("Vertices", &obj2);
+  Array *a = new Array(doc->getXRef());
+  a->add(Object(0.));
+  a->add(Object(0.));
+  annotObj.dictSet("Vertices", Object(a));
 
   initialize(docA, annotObj.getDict());
 }
@@ -5744,7 +5508,8 @@ AnnotPolygon::~AnnotPolygon() {
 void AnnotPolygon::initialize(PDFDoc *docA, Dict* dict) {
   Object obj1;
 
-  if (dict->lookup("Subtype", &obj1)->isName()) {
+  obj1 = dict->lookup("Subtype");
+  if (obj1.isName()) {
     GooString typeName(obj1.getName());
     if (!typeName.cmp("Polygon")) {
       type = typePolygon;
@@ -5752,60 +5517,58 @@ void AnnotPolygon::initialize(PDFDoc *docA, Dict* dict) {
       type = typePolyLine;
     }
   }
-  obj1.free();
 
-  if (dict->lookup("Vertices", &obj1)->isArray()) {
+  obj1 = dict->lookup("Vertices");
+  if (obj1.isArray()) {
     vertices = new AnnotPath(obj1.getArray());
   } else {
     vertices = new AnnotPath();
     error(errSyntaxError, -1, "Bad Annot Polygon Vertices");
     ok = gFalse;
   }
-  obj1.free();
-
-  if (dict->lookup("LE", &obj1)->isArray() && obj1.arrayGetLength() == 2) {
-    Object obj2;
 
-    if(obj1.arrayGet(0, &obj2)->isString())
+  obj1 = dict->lookup("LE");
+  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+    Object obj2 = obj1.arrayGet(0);
+    if(obj2.isString())
       startStyle = parseAnnotLineEndingStyle(obj2.getString());
     else
       startStyle = annotLineEndingNone;
-    obj2.free();
 
-    if(obj1.arrayGet(1, &obj2)->isString())
+    obj2 = obj1.arrayGet(1);
+    if(obj2.isString())
       endStyle = parseAnnotLineEndingStyle(obj2.getString());
     else
       endStyle = annotLineEndingNone;
-    obj2.free();
 
   } else {
     startStyle = endStyle = annotLineEndingNone;
   }
-  obj1.free();
 
-  if (dict->lookup("IC", &obj1)->isArray()) {
+  obj1 = dict->lookup("IC");
+  if (obj1.isArray()) {
     interiorColor = new AnnotColor(obj1.getArray());
   } else {
     interiorColor = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("BS", &obj1)->isDict()) {
+  obj1 = dict->lookup("BS");
+  if (obj1.isDict()) {
     delete border;
     border = new AnnotBorderBS(obj1.getDict());
   } else if (!border) {
     border = new AnnotBorderBS();
   }
-  obj1.free();
 
-  if (dict->lookup("BE", &obj1)->isDict()) {
+  obj1 = dict->lookup("BE");
+  if (obj1.isDict()) {
     borderEffect = new AnnotBorderEffect(obj1.getDict());
   } else {
     borderEffect = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("IT", &obj1)->isName()) {
+  obj1 = dict->lookup("IT");
+  if (obj1.isName()) {
     const char *intentName = obj1.getName();
 
     if(!strcmp(intentName, "PolygonCloud")) {
@@ -5818,56 +5581,51 @@ void AnnotPolygon::initialize(PDFDoc *docA, Dict* dict) {
   } else {
     intent = polygonCloud;
   }
-  obj1.free();
 }
 
 void AnnotPolygon::setType(AnnotSubtype new_type) {
-  Object obj1;
+  const char *typeName;
 
   switch (new_type) {
     case typePolygon:
-      obj1.initName("Polygon");
+      typeName = "Polygon";
       break;
     case typePolyLine:
-      obj1.initName("PolyLine");
+      typeName = "PolyLine";
       break;
     default:
       assert(!"Invalid subtype");
   }
 
   type = new_type;
-  update("Subtype", &obj1);
+  update("Subtype", Object(objName, typeName));
   invalidateAppearance();
 }
 
 void AnnotPolygon::setVertices(AnnotPath *path) {
-  Object obj1, obj2;
   delete vertices;
 
-  obj1.initArray(xref);
-
+  Array *a = new Array(xref);
   for (int i = 0; i < path->getCoordsLength(); i++) {
-    obj1.arrayAdd (obj2.initReal (path->getX(i)));
-    obj1.arrayAdd (obj2.initReal (path->getY(i)));
+    a->add(Object(path->getX(i)));
+    a->add(Object(path->getY(i)));
   }
 
-  vertices = new AnnotPath(obj1.getArray());
+  vertices = new AnnotPath(a);
 
-  update("Vertices", &obj1);
+  update("Vertices", Object(a));
   invalidateAppearance();
 }
 
 void AnnotPolygon::setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end) {
-  Object obj1, obj2;
-
   startStyle = start;
   endStyle = end;
 
-  obj1.initArray(xref);
-  obj1.arrayAdd( obj2.initName(convertAnnotLineEndingStyle( startStyle )) );
-  obj1.arrayAdd( obj2.initName(convertAnnotLineEndingStyle( endStyle )) );
+  Array *a = new Array(xref);
+  a->add( Object(objName, convertAnnotLineEndingStyle( startStyle )) );
+  a->add( Object(objName, convertAnnotLineEndingStyle( endStyle )) );
 
-  update("LE", &obj1);
+  update("LE", Object(a));
   invalidateAppearance();
 }
 
@@ -5875,9 +5633,8 @@ void AnnotPolygon::setInteriorColor(AnnotColor *new_color) {
   delete interiorColor;
 
   if (new_color) {
-    Object obj1;
-    new_color->writeToObject(xref, &obj1);
-    update ("IC", &obj1);
+    Object obj1 = new_color->writeToObject(xref);
+    update ("IC", std::move(obj1));
     interiorColor = new_color;
   } else {
     interiorColor = NULL;
@@ -5886,20 +5643,19 @@ void AnnotPolygon::setInteriorColor(AnnotColor *new_color) {
 }
 
 void AnnotPolygon::setIntent(AnnotPolygonIntent new_intent) {
-  Object obj1;
+  const char *intentName;
 
   intent = new_intent;
   if (new_intent == polygonCloud)
-    obj1.initName("PolygonCloud");
+    intentName = "PolygonCloud";
   else if (new_intent == polylineDimension)
-    obj1.initName("PolyLineDimension");
+    intentName = "PolyLineDimension";
   else // polygonDimension
-    obj1.initName("PolygonDimension");
-  update ("IT", &obj1);
+    intentName = "PolygonDimension";
+  update ("IT", Object(objName, intentName));
 }
 
 void AnnotPolygon::draw(Gfx *gfx, GBool printing) {
-  Object obj;
   double ca = 1;
 
   if (!isVisible (printing))
@@ -5949,22 +5705,20 @@ void AnnotPolygon::draw(Gfx *gfx, GBool printing) {
     double bbox[4];
     appearBBox->getBBoxRect(bbox);
     if (ca == 1) {
-      createForm(bbox, gFalse, NULL, &appearance);
+      appearance = createForm(bbox, gFalse, nullptr);
     } else {
-      Object aStream, resDict;
-
-      createForm(bbox, gTrue, NULL, &aStream);
+      Object aStream = createForm(bbox, gTrue, nullptr);
       delete appearBuf;
 
       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-      createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-      createForm(bbox, gFalse, &resDict, &appearance);
+      Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+      appearance = createForm(bbox, gFalse, resDict);
     }
     delete appearBuf;
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
@@ -5974,7 +5728,6 @@ void AnnotPolygon::draw(Gfx *gfx, GBool printing) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   }
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -5986,7 +5739,7 @@ AnnotCaret::AnnotCaret(PDFDoc *docA, PDFRectangle *rect) :
 
   type = typeCaret;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("Caret"));
+  annotObj.dictSet ("Subtype", Object(objName, "Caret"));
   initialize(docA, annotObj.getDict());
 }
 
@@ -6004,7 +5757,8 @@ void AnnotCaret::initialize(PDFDoc *docA, Dict* dict) {
   Object obj1;
 
   symbol = symbolNone;
-  if (dict->lookup("Sy", &obj1)->isName()) {
+  obj1 = dict->lookup("Sy");
+  if (obj1.isName()) {
     GooString typeName(obj1.getName());
     if (!typeName.cmp("P")) {
       symbol = symbolP;
@@ -6012,22 +5766,18 @@ void AnnotCaret::initialize(PDFDoc *docA, Dict* dict) {
       symbol = symbolNone;
     }
   }
-  obj1.free();
 
-  if (dict->lookup("RD", &obj1)->isArray()) {
+  obj1 = dict->lookup("RD");
+  if (obj1.isArray()) {
     caretRect = parseDiffRectangle(obj1.getArray(), rect);
   } else {
     caretRect = NULL;
   }
-  obj1.free();
-
 }
 
 void AnnotCaret::setSymbol(AnnotCaretSymbol new_symbol) {
-  Object obj1;
-  obj1.initName( new_symbol == symbolP ? "P" : "None" );
   symbol = new_symbol;
-  update("Sy", &obj1);
+  update("Sy", Object(objName, new_symbol == symbolP ? "P" : "None"));
   invalidateAppearance();
 }
 
@@ -6040,15 +5790,16 @@ AnnotInk::AnnotInk(PDFDoc *docA, PDFRectangle *rect) :
 
   type = typeInk;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("Ink"));
+  annotObj.dictSet ("Subtype", Object(objName, "Ink"));
 
   // Store dummy path with one null vertex only
-  Object obj2, obj3, obj4;
-  obj2.initArray (doc->getXRef());
-  obj2.arrayAdd (obj3.initArray (doc->getXRef()));
-  obj3.arrayAdd (obj4.initReal (0));
-  obj3.arrayAdd (obj4.initReal (0));
-  annotObj.dictSet ("InkList", &obj2);
+  Object obj3, obj4;
+  Array *inkList = new Array(doc->getXRef());
+  Array *vList = new Array(doc->getXRef());
+  vList->add(Object(0.));
+  vList->add(Object(0.));
+  inkList->add(Object(vList));
+  annotObj.dictSet("InkList", Object(inkList));
 
   initialize(docA, annotObj.getDict());
 }
@@ -6066,7 +5817,8 @@ AnnotInk::~AnnotInk() {
 void AnnotInk::initialize(PDFDoc *docA, Dict* dict) {
   Object obj1;
 
-  if (dict->lookup("InkList", &obj1)->isArray()) {
+  obj1 = dict->lookup("InkList");
+  if (obj1.isArray()) {
     parseInkList(obj1.getArray());
   } else {
     inkListLength = 0;
@@ -6074,27 +5826,25 @@ void AnnotInk::initialize(PDFDoc *docA, Dict* dict) {
     error(errSyntaxError, -1, "Bad Annot Ink List");
     ok = gFalse;
   }
-  obj1.free();
 
-  if (dict->lookup("BS", &obj1)->isDict()) {
+  obj1 = dict->lookup("BS");
+  if (obj1.isDict()) {
     delete border;
     border = new AnnotBorderBS(obj1.getDict());
   } else if (!border) {
     border = new AnnotBorderBS();
   }
-  obj1.free();
 }
 
 void AnnotInk::writeInkList(AnnotPath **paths, int n_paths, Array *dest_array) {
-  Object obj1, obj2;
   for (int i = 0; i < n_paths; ++i) {
     AnnotPath *path = paths[i];
-    obj1.initArray (xref);
+    Array *a = new Array(xref);
     for (int j = 0; j < path->getCoordsLength(); ++j) {
-      obj1.arrayAdd (obj2.initReal (path->getX(j)));
-      obj1.arrayAdd (obj2.initReal (path->getY(j)));
+      a->add(Object(path->getX(j)));
+      a->add(Object(path->getY(j)));
     }
-    dest_array->add (&obj1);
+    dest_array->add(Object(a));
   }
 }
 
@@ -6103,10 +5853,9 @@ void AnnotInk::parseInkList(Array *array) {
   inkList = (AnnotPath **) gmallocn ((inkListLength), sizeof(AnnotPath *));
   memset(inkList, 0, inkListLength * sizeof(AnnotPath *));
   for (int i = 0; i < inkListLength; i++) {
-    Object obj2;
-    if (array->get(i, &obj2)->isArray())
+    Object obj2 = array->get(i);
+    if (obj2.isArray())
       inkList[i] = new AnnotPath(obj2.getArray());
-    obj2.free();
   }
 }
 
@@ -6119,20 +5868,17 @@ void AnnotInk::freeInkList() {
 }
 
 void AnnotInk::setInkList(AnnotPath **paths, int n_paths) {
-  Object obj1;
-
   freeInkList();
 
-  obj1.initArray (xref);
-  writeInkList(paths, n_paths, obj1.getArray());
+  Array *a = new Array(xref);
+  writeInkList(paths, n_paths, a);
 
-  parseInkList(obj1.getArray());
-  annotObj.dictSet ("InkList", &obj1);
+  parseInkList(a);
+  annotObj.dictSet ("InkList", Object(a));
   invalidateAppearance();
 }
 
 void AnnotInk::draw(Gfx *gfx, GBool printing) {
-  Object obj;
   double ca = 1;
 
   if (!isVisible (printing))
@@ -6173,22 +5919,20 @@ void AnnotInk::draw(Gfx *gfx, GBool printing) {
     double bbox[4];
     appearBBox->getBBoxRect(bbox);
     if (ca == 1) {
-      createForm(bbox, gFalse, NULL, &appearance);
+      appearance = createForm(bbox, gFalse, nullptr);
     } else {
-      Object aStream, resDict;
-
-      createForm(bbox, gTrue, NULL, &aStream);
+      Object aStream = createForm(bbox, gTrue, nullptr);
       delete appearBuf;
 
       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-      createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-      createForm(bbox, gFalse, &resDict, &appearance);
+      Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+      appearance = createForm(bbox, gFalse, resDict);
     }
     delete appearBuf;
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
@@ -6198,7 +5942,6 @@ void AnnotInk::draw(Gfx *gfx, GBool printing) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   }
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -6210,11 +5953,8 @@ AnnotFileAttachment::AnnotFileAttachment(PDFDoc *docA, PDFRectangle *rect, GooSt
 
   type = typeFileAttachment;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("FileAttachment"));
-
-  Object obj2;
-  obj2.initString(filename->copy());
-  annotObj.dictSet ("FS", &obj2);
+  annotObj.dictSet("Subtype", Object(objName, "FileAttachment"));
+  annotObj.dictSet("FS", Object(filename->copy()));
 
   initialize(docA, annotObj.getDict());
 }
@@ -6226,29 +5966,26 @@ AnnotFileAttachment::AnnotFileAttachment(PDFDoc *docA, Dict *dict, Object *obj)
 }
 
 AnnotFileAttachment::~AnnotFileAttachment() {
-  file.free();
-
-  if (name)
-    delete name;
+  delete name;
 }
 
 void AnnotFileAttachment::initialize(PDFDoc *docA, Dict* dict) {
   Object obj1;
 
-  if (dict->lookup("FS", &obj1)->isDict() || dict->lookup("FS", &obj1)->isString()) {
-    obj1.copy(&file);
+  obj1 = dict->lookup("FS");
+  if (obj1.isDict() || obj1.isString()) {
+    file = obj1.copy();
   } else {
     error(errSyntaxError, -1, "Bad Annot File Attachment");
     ok = gFalse;
   }
-  obj1.free();
 
-  if (dict->lookup("Name", &obj1)->isName()) {
+  obj1 = dict->lookup("Name");
+  if (obj1.isName()) {
     name = new GooString(obj1.getName());
   } else {
     name = new GooString("PushPin");
   }
-  obj1.free();
 }
 
 #define ANNOT_FILE_ATTACHMENT_AP_PUSHPIN                                         \
@@ -6364,7 +6101,6 @@ void AnnotFileAttachment::initialize(PDFDoc *docA, Dict* dict) {
   "19.5 17.699 20.91 17.418 22.5 17.5 c S\n"
 
 void AnnotFileAttachment::draw(Gfx *gfx, GBool printing) {
-  Object obj;
   double ca = 1;
 
   if (!isVisible (printing))
@@ -6395,26 +6131,22 @@ void AnnotFileAttachment::draw(Gfx *gfx, GBool printing) {
     bbox[0] = bbox[1] = 0;
     bbox[2] = bbox[3] = 24;
     if (ca == 1) {
-      createForm (bbox, gFalse, NULL, &appearance);
+      appearance = createForm (bbox, gFalse, nullptr);
     } else {
-      Object aStream;
-
-      createForm (bbox, gTrue, NULL, &aStream);
+      Object aStream = createForm (bbox, gTrue, nullptr);
       delete appearBuf;
 
-      Object resDict;
       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-      createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-      createForm(bbox, gFalse, &resDict, &appearance);
+      Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+      appearance = createForm(bbox, gFalse, resDict);
     }
     delete appearBuf;
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  Object obj = appearance.fetch(gfx->getXRef());
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
 		 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -6426,13 +6158,11 @@ AnnotSound::AnnotSound(PDFDoc *docA, PDFRectangle *rect, Sound *soundA) :
 
   type = typeSound;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("Sound"));
+  annotObj.dictSet ("Subtype", Object(objName, "Sound"));
 
-  Object obj2;
   Stream *str = soundA->getStream();
-  obj2.initStream (str);
-  str->incRef(); //FIXME: initStream should do this?
-  annotObj.dictSet ("Sound", &obj2);
+  str->incRef();
+  annotObj.dictSet ("Sound", Object(str));
 
   initialize(docA, annotObj.getDict());
 }
@@ -6450,21 +6180,20 @@ AnnotSound::~AnnotSound() {
 }
 
 void AnnotSound::initialize(PDFDoc *docA, Dict* dict) {
-  Object obj1;
+  Object obj1 = dict->lookup("Sound");
 
-  sound = Sound::parseSound(dict->lookup("Sound", &obj1));
+  sound = Sound::parseSound(&obj1);
   if (!sound) {
     error(errSyntaxError, -1, "Bad Annot Sound");
     ok = gFalse;
   }
-  obj1.free();
 
-  if (dict->lookup("Name", &obj1)->isName()) {
+  obj1 = dict->lookup("Name");
+  if (obj1.isName()) {
     name = new GooString(obj1.getName());
   } else {
     name = new GooString("Speaker");
   }
-  obj1.free();
 }
 
 #define ANNOT_SOUND_AP_SPEAKER                                               \
@@ -6558,25 +6287,22 @@ void AnnotSound::draw(Gfx *gfx, GBool printing) {
     bbox[0] = bbox[1] = 0;
     bbox[2] = bbox[3] = 24;
     if (ca == 1) {
-      createForm(bbox, gFalse, NULL, &appearance);
+      appearance = createForm(bbox, gFalse, nullptr);
     } else {
-      Object aStream, resDict;
-
-      createForm(bbox, gTrue, NULL, &aStream);
+      Object aStream = createForm(bbox, gTrue, nullptr);
       delete appearBuf;
 
       appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
-      createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
-      createForm(bbox, gFalse, &resDict, &appearance);
+      Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, NULL);
+      appearance = createForm(bbox, gFalse, resDict);
     }
     delete appearBuf;
   }
 
   // draw the appearance stream
-  appearance.fetch(gfx->getXRef(), &obj);
+  obj = appearance.fetch(gfx->getXRef());
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
 		 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
-  obj.free();
 }
 
 //------------------------------------------------------------------------
@@ -6588,7 +6314,7 @@ Annot3D::Annot3D(PDFDoc *docA, PDFRectangle *rect) :
 
   type = type3D;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("3D"));
+  annotObj.dictSet ("Subtype", Object(objName, "3D"));
 
   initialize(docA, annotObj.getDict());
 }
@@ -6605,20 +6331,19 @@ Annot3D::~Annot3D() {
 }
 
 void Annot3D::initialize(PDFDoc *docA, Dict* dict) {
-  Object obj1;
-
-  if (dict->lookup("3DA", &obj1)->isDict()) {
+  Object obj1 = dict->lookup("3DA");
+  if (obj1.isDict()) {
     activation = new Activation(obj1.getDict());
   } else {
     activation = NULL;
   }
-  obj1.free();
 }
 
 Annot3D::Activation::Activation(Dict *dict) {
   Object obj1;
 
-  if (dict->lookup("A", &obj1)->isName()) {
+  obj1 = dict->lookup("A");
+  if (obj1.isName()) {
     const char *name = obj1.getName();
 
     if(!strcmp(name, "PO")) {
@@ -6633,9 +6358,9 @@ Annot3D::Activation::Activation(Dict *dict) {
   } else {
     aTrigger = aTriggerUnknown;
   }
-  obj1.free();
 
-  if(dict->lookup("AIS", &obj1)->isName()) {
+  obj1 = dict->lookup("AIS");
+  if (obj1.isName()) {
     const char *name = obj1.getName();
 
     if(!strcmp(name, "I")) {
@@ -6648,9 +6373,9 @@ Annot3D::Activation::Activation(Dict *dict) {
   } else {
     aState = aStateUnknown;
   }
-  obj1.free();
 
-  if(dict->lookup("D", &obj1)->isName()) {
+  obj1 = dict->lookup("D");
+  if (obj1.isName()) {
     const char *name = obj1.getName();
 
     if(!strcmp(name, "PC")) {
@@ -6665,9 +6390,9 @@ Annot3D::Activation::Activation(Dict *dict) {
   } else {
     dTrigger = dTriggerUnknown;
   }
-  obj1.free();
 
-  if(dict->lookup("DIS", &obj1)->isName()) {
+  obj1 = dict->lookup("DIS");
+  if (obj1.isName()) {
     const char *name = obj1.getName();
 
     if(!strcmp(name, "U")) {
@@ -6682,21 +6407,20 @@ Annot3D::Activation::Activation(Dict *dict) {
   } else {
     dState = dStateUnknown;
   }
-  obj1.free();
 
-  if (dict->lookup("TB", &obj1)->isBool()) {
+  obj1 = dict->lookup("TB");
+  if (obj1.isBool()) {
     displayToolbar = obj1.getBool();
   } else {
     displayToolbar = gTrue;
   }
-  obj1.free();
 
-  if (dict->lookup("NP", &obj1)->isBool()) {
+  obj1 = dict->lookup("NP");
+  if (obj1.isBool()) {
     displayNavigation = obj1.getBool();
   } else {
     displayNavigation = gFalse;
   }
-  obj1.free();
 }
 
 //------------------------------------------------------------------------
@@ -6708,7 +6432,7 @@ AnnotRichMedia::AnnotRichMedia(PDFDoc *docA, PDFRectangle *rect) :
 
   type = typeRichMedia;
 
-  annotObj.dictSet ("Subtype", obj1.initName ("RichMedia"));
+  annotObj.dictSet ("Subtype", Object(objName, "RichMedia"));
 
   initialize(docA, annotObj.getDict());
 }
@@ -6725,21 +6449,19 @@ AnnotRichMedia::~AnnotRichMedia() {
 }
 
 void AnnotRichMedia::initialize(PDFDoc *docA, Dict* dict) {
-  Object obj1;
-
-  if (dict->lookup("RichMediaContent", &obj1)->isDict()) {
+  Object obj1 = dict->lookup("RichMediaContent");
+  if (obj1.isDict()) {
     content = new AnnotRichMedia::Content(obj1.getDict());
   } else {
     content = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("RichMediaSettings", &obj1)->isDict()) {
+  obj1 = dict->lookup("RichMediaSettings");
+  if (obj1.isDict()) {
     settings = new AnnotRichMedia::Settings(obj1.getDict());
   } else {
     settings = NULL;
   }
-  obj1.free();
 }
 
 AnnotRichMedia::Content* AnnotRichMedia::getContent() const {
@@ -6751,21 +6473,19 @@ AnnotRichMedia::Settings* AnnotRichMedia::getSettings() const {
 }
 
 AnnotRichMedia::Settings::Settings(Dict *dict) {
-  Object obj1;
-
-  if (dict->lookup("Activation", &obj1)->isDict()) {
+  Object obj1 = dict->lookup("Activation");
+  if (obj1.isDict()) {
     activation = new AnnotRichMedia::Activation(obj1.getDict());
   } else {
     activation = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("Deactivation", &obj1)->isDict()) {
+  obj1 = dict->lookup("Deactivation");
+  if (obj1.isDict()) {
     deactivation = new AnnotRichMedia::Deactivation(obj1.getDict());
   } else {
     deactivation = NULL;
   }
-  obj1.free();
 }
 
 AnnotRichMedia::Settings::~Settings() {
@@ -6782,9 +6502,8 @@ AnnotRichMedia::Deactivation* AnnotRichMedia::Settings::getDeactivation() const
 }
 
 AnnotRichMedia::Activation::Activation(Dict *dict) {
-  Object obj1;
-
-  if (dict->lookup("Condition", &obj1)->isName()) {
+  Object obj1 = dict->lookup("Condition");
+  if (obj1.isName()) {
     const char *name = obj1.getName();
 
     if (!strcmp(name, "PO")) {
@@ -6799,7 +6518,6 @@ AnnotRichMedia::Activation::Activation(Dict *dict) {
   } else {
     condition = conditionUserAction;
   }
-  obj1.free();
 }
 
 AnnotRichMedia::Activation::Condition AnnotRichMedia::Activation::getCondition() const {
@@ -6807,9 +6525,8 @@ AnnotRichMedia::Activation::Condition AnnotRichMedia::Activation::getCondition()
 }
 
 AnnotRichMedia::Deactivation::Deactivation(Dict *dict) {
-  Object obj1;
-
-  if (dict->lookup("Condition", &obj1)->isName()) {
+  Object obj1 = dict->lookup("Condition");
+  if (obj1.isName()) {
     const char *name = obj1.getName();
 
     if (!strcmp(name, "PC")) {
@@ -6824,7 +6541,6 @@ AnnotRichMedia::Deactivation::Deactivation(Dict *dict) {
   } else {
     condition = conditionUserAction;
   }
-  obj1.free();
 }
 
 AnnotRichMedia::Deactivation::Condition AnnotRichMedia::Deactivation::getCondition() const {
@@ -6832,57 +6548,48 @@ AnnotRichMedia::Deactivation::Condition AnnotRichMedia::Deactivation::getConditi
 }
 
 AnnotRichMedia::Content::Content(Dict *dict) {
-  Object obj1;
-
-  if (dict->lookup("Configurations", &obj1)->isArray()) {
+  Object obj1 = dict->lookup("Configurations");
+  if (obj1.isArray()) {
     nConfigurations = obj1.arrayGetLength();
 
     configurations = (Configuration **)gmallocn(nConfigurations, sizeof(Configuration *));
 
     for (int i = 0; i < nConfigurations; ++i) {
-      Object obj2;
-
-      if (obj1.arrayGet(i, &obj2)->isDict()) {
+      Object obj2 = obj1.arrayGet(i);
+      if (obj2.isDict()) {
         configurations[i] = new AnnotRichMedia::Configuration(obj2.getDict());
       } else {
         configurations[i] = NULL;
       }
-      obj2.free();
     }
   } else {
     nConfigurations = 0;
     configurations = NULL;
   }
-  obj1.free();
 
   nAssets = 0;
   assets = NULL;
-  if (dict->lookup("Assets", &obj1)->isDict()) {
-    Object obj2;
-
-    if (obj1.getDict()->lookup("Names", &obj2)->isArray()) {
+  obj1 = dict->lookup("Assets");
+  if (obj1.isDict()) {
+    Object obj2 = obj1.getDict()->lookup("Names");
+    if (obj2.isArray()) {
       nAssets = obj2.arrayGetLength() / 2;
 
       assets = (Asset **)gmallocn(nAssets, sizeof(Asset *));
 
       int counter = 0;
       for (int i = 0; i < obj2.arrayGetLength(); i += 2) {
-        Object objKey;
-
         assets[counter] = new AnnotRichMedia::Asset;
 
-        obj2.arrayGet(i, &objKey);
-        obj2.arrayGet(i + 1, &assets[counter]->fileSpec);
+        Object objKey = obj2.arrayGet(i);
+        assets[counter]->fileSpec = obj2.arrayGet(i + 1);
 
         assets[counter]->name = new GooString( objKey.getString() );
         ++counter;
 
-        objKey.free();
       }
     }
-    obj2.free();
   }
-  obj1.free();
 }
 
 AnnotRichMedia::Content::~Content() {
@@ -6929,7 +6636,6 @@ AnnotRichMedia::Asset::Asset()
 AnnotRichMedia::Asset::~Asset()
 {
   delete name;
-  fileSpec.free();
 }
 
 GooString* AnnotRichMedia::Asset::getName() const {
@@ -6942,36 +6648,33 @@ Object* AnnotRichMedia::Asset::getFileSpec() const {
 
 AnnotRichMedia::Configuration::Configuration(Dict *dict)
 {
-  Object obj1;
-
-  if (dict->lookup("Instances", &obj1)->isArray()) {
+  Object obj1 = dict->lookup("Instances");
+  if (obj1.isArray()) {
     nInstances = obj1.arrayGetLength();
 
     instances = (Instance **)gmallocn(nInstances, sizeof(Instance *));
 
     for (int i = 0; i < nInstances; ++i) {
-      Object obj2;
-
-      if (obj1.arrayGet(i, &obj2)->isDict()) {
+      Object obj2 = obj1.arrayGet(i);
+      if (obj2.isDict()) {
         instances[i] = new AnnotRichMedia::Instance(obj2.getDict());
       } else {
         instances[i] = NULL;
       }
-      obj2.free();
     }
   } else {
     instances = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("Name", &obj1)->isString()) {
+  obj1 = dict->lookup("Name");
+  if (obj1.isString()) {
     name = new GooString(obj1.getString());
   } else {
     name = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("Subtype", &obj1)->isName()) {
+  obj1 = dict->lookup("Subtype");
+  if (obj1.isName()) {
     const char *name = obj1.getName();
 
     if (!strcmp(name, "3D")) {
@@ -7006,7 +6709,6 @@ AnnotRichMedia::Configuration::Configuration(Dict *dict)
       }
     }
   }
-  obj1.free();
 }
 
 AnnotRichMedia::Configuration::~Configuration()
@@ -7041,9 +6743,7 @@ AnnotRichMedia::Configuration::Type AnnotRichMedia::Configuration::getType() con
 
 AnnotRichMedia::Instance::Instance(Dict *dict)
 {
-  Object obj1;
-
-  dict->lookup("Subtype", &obj1);
+  Object obj1 = dict->lookup("Subtype");
   const char *name = obj1.isName() ? obj1.getName() : "";
 
   if (!strcmp(name, "3D")) {
@@ -7057,14 +6757,13 @@ AnnotRichMedia::Instance::Instance(Dict *dict)
   } else {
     type = typeFlash;
   }
-  obj1.free();
 
-  if (dict->lookup("Params", &obj1)->isDict()) {
+  obj1 = dict->lookup("Params");
+  if (obj1.isDict()) {
     params = new AnnotRichMedia::Params(obj1.getDict());
   } else {
     params = NULL;
   }
-  obj1.free();
 }
 
 AnnotRichMedia::Instance::~Instance()
@@ -7082,14 +6781,12 @@ AnnotRichMedia::Params* AnnotRichMedia::Instance::getParams() const {
 
 AnnotRichMedia::Params::Params(Dict *dict)
 {
-  Object obj1;
-
-  if (dict->lookup("FlashVars", &obj1)->isString()) {
+  Object obj1 = dict->lookup("FlashVars");
+  if (obj1.isString()) {
     flashVars = new GooString(obj1.getString());
   } else {
     flashVars = NULL;
   }
-  obj1.free();
 }
 
 AnnotRichMedia::Params::~Params()
@@ -7107,7 +6804,6 @@ GooString* AnnotRichMedia::Params::getFlashVars() const {
 
 Annots::Annots(PDFDoc *docA, int page, Object *annotsObj) {
   Annot *annot;
-  Object obj1;
   int i;
 
   doc = docA;
@@ -7120,9 +6816,9 @@ Annots::Annots(PDFDoc *docA, int page, Object *annotsObj) {
       //get the Ref to this annot and pass it to Annot constructor 
       //this way, it'll be possible for the annot to retrieve the corresponding
       //form widget
-      Object obj2;
-      if (annotsObj->arrayGet(i, &obj1)->isDict()) {
-        annotsObj->arrayGetNF(i, &obj2);
+      Object obj1 = annotsObj->arrayGet(i);
+      if (obj1.isDict()) {
+	Object obj2 = annotsObj->arrayGetNF(i);
         annot = createAnnot (obj1.getDict(), &obj2);
         if (annot) {
           if (annot->isOk()) {
@@ -7132,8 +6828,6 @@ Annots::Annots(PDFDoc *docA, int page, Object *annotsObj) {
           annot->decRefCnt();
         }
       }
-      obj2.free();
-      obj1.free();
     }
   }
 }
@@ -7168,10 +6862,9 @@ GBool Annots::removeAnnot(Annot *annot) {
 }
 
 Annot *Annots::createAnnot(Dict* dict, Object *obj) {
-  Annot *annot = NULL;
-  Object obj1;
-
-  if (dict->lookup("Subtype", &obj1)->isName()) {
+  Annot *annot = nullptr;
+  Object obj1 = dict->lookup("Subtype");
+  if (obj1.isName()) {
     const char *typeName = obj1.getName();
 
     if (!strcmp(typeName, "Text")) {
@@ -7241,19 +6934,15 @@ Annot *Annots::createAnnot(Dict* dict, Object *obj) {
        * Here we only care about popup annots without a
        * markup annotation associated
        */
-      Object obj2;
-
-      if (dict->lookup("Parent", &obj2)->isNull())
+      Object obj2 = dict->lookup("Parent");
+      if (obj2.isNull())
         annot = new AnnotPopup(doc, dict, obj);
       else
         annot = NULL;
-      
-      obj2.free();
     } else {
       annot = new Annot(doc, dict, obj);
     }
   }
-  obj1.free();
 
   return annot;
 }
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 87ba9c38..a84900d9 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -239,7 +239,7 @@ public:
   virtual double *getDash() const { return dash; }
   virtual AnnotBorderStyle getStyle() const { return style; }
 
-  virtual void writeToObject(XRef *xref, Object *obj1) const = 0;
+  virtual Object writeToObject(XRef *xref) const = 0;
 
 protected:
   AnnotBorder();
@@ -271,7 +271,7 @@ public:
 
 private:
   AnnotBorderType getType() const override { return typeArray; }
-  void writeToObject(XRef *xref, Object *obj1) const override;
+  Object writeToObject(XRef *xref) const override;
 
   double horizontalCorner;          // (Default 0)
   double verticalCorner;            // (Default 0)
@@ -290,7 +290,7 @@ public:
 
 private:
   AnnotBorderType getType() const override { return typeBS; }
-  void writeToObject(XRef *xref, Object *obj1) const override;
+  Object writeToObject(XRef *xref) const override;
 
   const char *getStyleName() const;
 
@@ -324,7 +324,7 @@ public:
   AnnotColorSpace getSpace() const { return (AnnotColorSpace) length; }
   const double *getValues() const { return values; }
 
-  void writeToObject(XRef *xref, Object *dest) const;
+  Object writeToObject(XRef *xref) const;
 
 private:
 
@@ -385,7 +385,7 @@ public:
   ~AnnotAppearance();
 
   // State is ignored if no subdictionary is present
-  void getAppearanceStream(AnnotAppearanceType type, const char *state, Object *dest);
+  Object getAppearanceStream(AnnotAppearanceType type, const char *state);
 
   // Access keys in normal appearance subdictionary (N)
   GooString * getStateKey(int i);
@@ -564,7 +564,7 @@ public:
 
   virtual void draw(Gfx *gfx, GBool printing);
   // Get the resource dict of the appearance stream
-  virtual Object *getAppearanceResDict(Object *dest);
+  virtual Object getAppearanceResDict();
 
   GBool match(Ref *refA)
     { return ref.num == refA->num && ref.gen == refA->gen; }
@@ -638,15 +638,15 @@ protected:
 		  double *width, double widthLimit, int *charCount,
 		  GBool noReencode);
   void writeString(GooString *str, GooString *appearBuf);
-  void createForm(double *bbox, GBool transparencyGroup, Object *resDict, Object *aStream);
-  void createResourcesDict(const char *formName, Object *formStream, const char *stateName,
-			   double opacity, const char *blendMode, Object *resDict);
+  Object createForm(double *bbox, GBool transparencyGroup, Dict *resDict);
+  Dict *createResourcesDict(const char *formName, Object &&formStream, const char *stateName,
+			   double opacity, const char *blendMode);
   GBool isVisible(GBool printing);
   int getRotation() const;
 
   // Updates the field key of the annotation dictionary
   // and sets M to the current time
-  void update(const char *key, Object *value);
+  void update(const char *key, Object &&value);
 
   // Delete appearance streams and reset appearance state
   void invalidateAppearance();
@@ -698,7 +698,6 @@ public:
   AnnotPopup(PDFDoc *docA, Dict *dict, Object *obj);
   ~AnnotPopup();
 
-  Object *getParent(Object *obj) { return parent.fetch (xref, obj); }
   Object *getParentNF() { return &parent; }
   void setParent(Object *parentA);
   void setParent(Annot *parentA);
@@ -923,7 +922,7 @@ public:
   ~AnnotFreeText();
 
   void draw(Gfx *gfx, GBool printing) override;
-  Object *getAppearanceResDict(Object *dest) override;
+  Object getAppearanceResDict() override;
   void setContents(GooString *new_content) override;
 
   void setAppearanceString(GooString *new_string);
@@ -987,7 +986,7 @@ public:
   ~AnnotLine();
 
   void draw(Gfx *gfx, GBool printing) override;
-  Object *getAppearanceResDict(Object *dest) override;
+  Object getAppearanceResDict() override;
   void setContents(GooString *new_content) override;
 
   void setVertices(double x1, double y1, double x2, double y2);
diff --git a/poppler/Array.cc b/poppler/Array.cc
index 131e4133..c2c4040d 100644
--- a/poppler/Array.cc
+++ b/poppler/Array.cc
@@ -65,14 +65,13 @@ Array::~Array() {
 #endif
 }
 
-Object *Array::copy(XRef *xrefA, Object *obj) {
+Object Array::copy(XRef *xrefA) {
   arrayLocker();
-  obj->initArray(xrefA);
+  Array *a = new Array(xrefA);
   for (int i = 0; i < length; ++i) {
-    Object obj1;
-    obj->arrayAdd(elems[i].copy(&obj1));
+    a->add(elems[i].copy());
   }
-  return obj;
+  return Object(a);
 }
 
 int Array::incRef() {
@@ -87,7 +86,7 @@ int Array::decRef() {
   return ref;
 }
 
-void Array::add(Object *elem) {
+void Array::add(Object &&elem) {
   arrayLocker();
   if (length == size) {
     if (length == 0) {
@@ -97,8 +96,8 @@ void Array::add(Object *elem) {
     }
     elems = (Object *)greallocn(elems, size, sizeof(Object));
   }
-  elems[length].initNullNoFree();
-  elem->shallowCopy(&elems[length]);
+  elems[length].initNullAfterMalloc();
+  elems[length] = std::move(elem);
   ++length;
 }
 
@@ -115,39 +114,36 @@ void Array::remove(int i) {
   memmove( elems + i, elems + i + 1, sizeof(elems[0]) * (length - i) );
 }
 
-Object *Array::get(int i, Object *obj, int recursion) {
+Object Array::get(int i, int recursion) {
   if (i < 0 || i >= length) {
 #ifdef DEBUG_MEM
     abort();
 #else
-    return obj->initNull();
+    return Object(objNull);
 #endif
   }
-  return elems[i].fetch(xref, obj, recursion);
+  return elems[i].fetch(xref, recursion);
 }
 
-Object *Array::getNF(int i, Object *obj) {
+Object Array::getNF(int i) {
   if (i < 0 || i >= length) {
 #ifdef DEBUG_MEM
     abort();
 #else
-    return obj->initNull();
+    return Object(objNull);
 #endif
   }
-  return elems[i].copy(obj);
+  return elems[i].copy();
 }
 
 GBool Array::getString(int i, GooString *string)
 {
-  Object obj;
-
-  if (getNF(i, &obj)->isString()) {
+  Object obj = getNF(i);
+  if (obj.isString()) {
     string->clear();
     string->append(obj.getString());
-    obj.free();
     return gTrue;
   } else {
-    obj.free();
     return gFalse;
   }
 }
diff --git a/poppler/Array.h b/poppler/Array.h
index 6240295a..bc522a00 100644
--- a/poppler/Array.h
+++ b/poppler/Array.h
@@ -57,18 +57,18 @@ public:
   int getLength() { return length; }
 
   // Copy array with new xref
-  Object *copy(XRef *xrefA, Object *obj);
+  Object copy(XRef *xrefA);
 
   // Add an element
   // elem becomes a dead object after this call
-  void add(Object *elem);
+  void add(Object &&elem);
 
   // Remove an element by position
   void remove(int i);
 
   // Accessors.
-  Object *get(int i, Object *obj, int resursion = 0);
-  Object *getNF(int i, Object *obj);
+  Object get(int i, int resursion = 0);
+  Object getNF(int i);
   GBool getString(int i, GooString *string);
 
 private:
diff --git a/poppler/CMap.cc b/poppler/CMap.cc
index 6731ab5a..40b497da 100644
--- a/poppler/CMap.cc
+++ b/poppler/CMap.cc
@@ -116,15 +116,11 @@ CMap *CMap::parse(CMapCache *cache, GooString *collectionA,
 }
 
 CMap *CMap::parse(CMapCache *cache, GooString *collectionA, Stream *str) {
-  Object obj1;
-  CMap *cMap;
-
-  cMap = new CMap(collectionA->copy(), NULL);
-
-  if (!str->getDict()->lookup("UseCMap", &obj1)->isNull()) {
+  CMap *cMap = new CMap(collectionA->copy(), NULL);
+  Object obj1 = str->getDict()->lookup("UseCMap");
+  if (!obj1.isNull()) {
     cMap->useCMap(cache, &obj1);
   }
-  obj1.free();
 
   str->reset();
   cMap->parse2(cache, &getCharFromStream, str);
diff --git a/poppler/CairoFontEngine.cc b/poppler/CairoFontEngine.cc
index 6676f898..60316ab0 100644
--- a/poppler/CairoFontEngine.cc
+++ b/poppler/CairoFontEngine.cc
@@ -708,7 +708,8 @@ _render_type3_glyph (cairo_scaled_font_t  *scaled_font,
   output_dev->startDoc(info->doc, info->fontEngine);
   output_dev->startPage (1, gfx->getState(), gfx->getXRef());
   output_dev->setInType3Char(gTrue);
-  gfx->display(charProcs->getVal(glyph, &charProc));
+  charProc = charProcs->getVal(glyph);
+  gfx->display(&charProc);
 
   output_dev->getType3GlyphWidth (&wx, &wy);
   cairo_matrix_transform_distance (&matrix, &wx, &wy);
@@ -727,7 +728,6 @@ _render_type3_glyph (cairo_scaled_font_t  *scaled_font,
 
   delete gfx;
   delete output_dev;
-  charProc.free();
 
   return CAIRO_STATUS_SUCCESS;
 }
diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index 2946c924..ea6d0ab4 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -2956,9 +2956,8 @@ void CairoOutputDev::setMimeData(GfxState *state, Stream *str, Object *ref,
       return;
   }
 
-  str->getDict()->lookup("ColorSpace", &obj);
+  obj = str->getDict()->lookup("ColorSpace");
   colorSpace = GfxColorSpace::parse(NULL, &obj, this, state);
-  obj.free();
 
   // colorspace in stream dict may be different from colorspace in jpx
   // data
diff --git a/poppler/Catalog.cc b/poppler/Catalog.cc
index c415c7f5..8ffff9dc 100644
--- a/poppler/Catalog.cc
+++ b/poppler/Catalog.cc
@@ -74,10 +74,6 @@
 //------------------------------------------------------------------------
 
 Catalog::Catalog(PDFDoc *docA) {
-  Object catDict, pagesDict, pagesDictRef;
-  Object obj, obj2;
-  Object optContentProps;
-
 #if MULTITHREADED
   gInitMutex(&mutex);
 #endif
@@ -107,44 +103,39 @@ Catalog::Catalog(PDFDoc *docA) {
   lastCachedPage = 0;
   markInfo = markInfoNull;
 
-  xref->getCatalog(&catDict);
+  Object catDict = xref->getCatalog();
   if (!catDict.isDict()) {
     error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-    goto err1;
+    ok = gFalse;
+    return;
   }
   // get the AcroForm dictionary
-  catDict.dictLookup("AcroForm", &acroForm);
+  acroForm = catDict.dictLookup("AcroForm");
 
   // read base URI
-  if (catDict.dictLookup("URI", &obj)->isDict()) {
-    if (obj.dictLookup("Base", &obj2)->isString()) {
+  Object obj = catDict.dictLookup("URI");
+  if (obj.isDict()) {
+    Object obj2 = obj.dictLookup("Base");
+    if (obj2.isString()) {
       baseURI = obj2.getString()->copy();
     }
-    obj2.free();
   }
-  obj.free();
 
   // get the Optional Content dictionary
-  if (catDict.dictLookup("OCProperties", &optContentProps)->isDict()) {
+  Object optContentProps = catDict.dictLookup("OCProperties");
+  if (optContentProps.isDict()) {
     optContent = new OCGs(&optContentProps, xref);
     if (!optContent->isOk ()) {
       delete optContent;
       optContent = NULL;
     }
   }
-  optContentProps.free();
 
   // actions
-  catDict.dictLookupNF("AA", &additionalActions);
+  additionalActions = catDict.dictLookupNF("AA");
 
   // get the ViewerPreferences dictionary
-  catDict.dictLookup("ViewerPreferences", &viewerPreferences);
-  catDict.free();
-  return;
-
- err1:
-  catDict.free();
-  ok = gFalse;
+  viewerPreferences = catDict.dictLookup("ViewerPreferences");
 }
 
 Catalog::~Catalog() {
@@ -175,8 +166,6 @@ Catalog::~Catalog() {
     gfree(pages);
   }
   gfree(pageRefs);
-  names.free();
-  dests.free();
   delete destNameTree;
   delete embeddedFileNameTree;
   delete jsNameTree;
@@ -188,45 +177,32 @@ Catalog::~Catalog() {
   delete optContent;
   delete viewerPrefs;
   delete structTreeRoot;
-  metadata.free();
-  outline.free();
-  acroForm.free();
-  viewerPreferences.free();
-  additionalActions.free();
 #if MULTITHREADED
   gDestroyMutex(&mutex);
 #endif
 }
 
 GooString *Catalog::readMetadata() {
-  GooString *s;
-  Dict *dict;
-  Object obj;
-
   catalogLocker();
   if (metadata.isNone()) {
-    Object catDict;
-
-    xref->getCatalog(&catDict);
+    Object catDict = xref->getCatalog();
     if (catDict.isDict()) {
-      catDict.dictLookup("Metadata", &metadata);
+      metadata = catDict.dictLookup("Metadata");
     } else {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-      metadata.initNull();
+      metadata.setToNull();
     }
-    catDict.free();
   }
 
   if (!metadata.isStream()) {
-    return NULL;
+    return nullptr;
   }
-  dict = metadata.streamGetDict();
-  if (!dict->lookup("Subtype", &obj)->isName("XML")) {
+  Object obj = metadata.streamGetDict()->lookup("Subtype");
+  if (!obj.isName("XML")) {
     error(errSyntaxWarning, -1, "Unknown Metadata type: '{0:s}'",
 	  obj.isName() ? obj.getName() : "???");
   }
-  obj.free();
-  s = new GooString();
+  GooString *s = new GooString();
   metadata.getStream()->fillGooString(s);
   metadata.streamClose();
   return s;
@@ -266,43 +242,33 @@ GBool Catalog::cachePageTree(int page)
 
   if (pagesList == NULL) {
 
-    Object catDict;
     Ref pagesRef;
 
-    xref->getCatalog(&catDict);
+    Object catDict = xref->getCatalog();
 
     if (catDict.isDict()) {
-      Object pagesDictRef;
-      if (catDict.dictLookupNF("Pages", &pagesDictRef)->isRef() &&
+      Object pagesDictRef = catDict.dictLookupNF("Pages");
+      if (pagesDictRef.isRef() &&
           pagesDictRef.getRefNum() >= 0 &&
           pagesDictRef.getRefNum() < xref->getNumObjects()) {
         pagesRef = pagesDictRef.getRef();
-        pagesDictRef.free();
       } else {
         error(errSyntaxError, -1, "Catalog dictionary does not contain a valid \"Pages\" entry");
-        pagesDictRef.free();
-        catDict.free();
         return gFalse;
       }
     } else {
       error(errSyntaxError, -1, "Could not find catalog dictionary");
-      catDict.free();
       return gFalse;
     }
 
-    Object obj;
-    catDict.dictLookup("Pages", &obj);
-    catDict.free();
+    Object obj = catDict.dictLookup("Pages");
     // This should really be isDict("Pages"), but I've seen at least one
     // PDF file where the /Type entry is missing.
     if (obj.isDict()) {
       obj.getDict()->incRef();
       pagesDict = obj.getDict();
-      obj.free();
-    }
-    else {
+    } else {
       error(errSyntaxError, -1, "Top-level pages object is wrong type ({0:s})", obj.getTypeName());
-      obj.free();
       return gFalse;
     }
 
@@ -340,12 +306,10 @@ GBool Catalog::cachePageTree(int page)
     if (pagesList->empty()) return gFalse;
 
     pagesDict = pagesList->back();
-    Object kids;
-    pagesDict->lookup("Kids", &kids);
+    Object kids = pagesDict->lookup("Kids");
     if (!kids.isArray()) {
       error(errSyntaxError, -1, "Kids object (page {0:d}) is wrong type ({1:s})",
             lastCachedPage+1, kids.getTypeName());
-      kids.free();
       return gFalse;
     }
 
@@ -360,17 +324,13 @@ GBool Catalog::cachePageTree(int page)
        attrsList->pop_back();
        kidsIdxList->pop_back();
        if (!kidsIdxList->empty()) kidsIdxList->back()++;
-       kids.free();
        continue;
     }
 
-    Object kidRef;
-    kids.arrayGetNF(kidsIdx, &kidRef);
+    Object kidRef = kids.arrayGetNF(kidsIdx);
     if (!kidRef.isRef()) {
       error(errSyntaxError, -1, "Kid object (page {0:d}) is not an indirect reference ({1:s})",
             lastCachedPage+1, kidRef.getTypeName());
-      kidRef.free();
-      kids.free();
       return gFalse;
     }
 
@@ -383,15 +343,11 @@ GBool Catalog::cachePageTree(int page)
     }
     if (loop) {
       error(errSyntaxError, -1, "Loop in Pages tree");
-      kidRef.free();
-      kids.free();
       kidsIdxList->back()++;
       continue;
     }
 
-    Object kid;
-    kids.arrayGet(kidsIdx, &kid);
-    kids.free();
+    Object kid = kids.arrayGet(kidsIdx);
     if (kid.isDict("Page") || (kid.isDict() && !kid.getDict()->hasKey("Kids"))) {
       PageAttrs *attrs = new PageAttrs(attrsList->back(), kid.getDict());
       Page *p = new Page(doc, lastCachedPage+1, kid.getDict(),
@@ -399,15 +355,11 @@ GBool Catalog::cachePageTree(int page)
       if (!p->isOk()) {
         error(errSyntaxError, -1, "Failed to create page (page {0:d})", lastCachedPage+1);
         delete p;
-        kidRef.free();
-        kid.free();
         return gFalse;
       }
 
       if (lastCachedPage >= numPages) {
         error(errSyntaxError, -1, "Page count in top-level pages object is incorrect");
-        kidRef.free();
-        kid.free();
         return gFalse;
       }
 
@@ -431,9 +383,6 @@ GBool Catalog::cachePageTree(int page)
             lastCachedPage+1, kid.getTypeName());
       kidsIdxList->back()++;
     }
-    kidRef.free();
-    kid.free();
-
   }
 
   return gFalse;
@@ -451,48 +400,28 @@ int Catalog::findPage(int num, int gen) {
 }
 
 LinkDest *Catalog::findDest(GooString *name) {
-  LinkDest *dest;
-  Object obj1;
-  GBool found;
-
   // try named destination dictionary then name tree
-  found = gFalse;
   if (getDests()->isDict()) {
-    if (!getDests()->dictLookup(name->getCString(), &obj1)->isNull())
-      found = gTrue;
-    else
-      obj1.free();
-  }
-  if (!found) {
-    catalogLocker();
-    if (getDestNameTree()->lookup(name, &obj1))
-      found = gTrue;
-    else
-      obj1.free();
+    Object obj1 = getDests()->dictLookup(name->getCString());
+    return createLinkDest(&obj1);
   }
-  if (!found)
-    return NULL;
 
-  dest = createLinkDest(&obj1);
-  obj1.free();
-
-  return dest;
+  catalogLocker();
+  Object obj2 = getDestNameTree()->lookup(name);
+  return createLinkDest(&obj2);
 }
 
 LinkDest *Catalog::createLinkDest(Object *obj)
 {
-  LinkDest *dest;
-  Object obj2;
-
-  dest = NULL;
+  LinkDest *dest = nullptr;
   if (obj->isArray()) {
     dest = new LinkDest(obj->getArray());
   } else if (obj->isDict()) {
-    if (obj->dictLookup("D", &obj2)->isArray())
+    Object obj2 = obj->dictLookup("D");
+    if (obj2.isArray())
       dest = new LinkDest(obj2.getArray());
     else
       error(errSyntaxWarning, -1, "Bad named destination value");
-    obj2.free();
   } else {
     error(errSyntaxWarning, -1, "Bad named destination value");
   }
@@ -528,34 +457,24 @@ char *Catalog::getDestsName(int i)
 
 LinkDest *Catalog::getDestsDest(int i)
 {
-  LinkDest *dest;
-  Object *obj, obj1;
-
-  obj= getDests();
+  Object *obj = getDests();
   if (!obj->isDict()) {
     return NULL;
   }
-  obj->dictGetVal(i, &obj1);
-  dest = createLinkDest(&obj1);
-  obj1.free();
-
-  return dest;
+  Object obj1 = obj->dictGetVal(i);
+  return createLinkDest(&obj1);
 }
 
 LinkDest *Catalog::getDestNameTreeDest(int i)
 {
-  LinkDest *dest;
   Object obj;
 
   catalogLocker();
   Object *aux = getDestNameTree()->getValue(i);
   if (aux) {
-    aux->fetch(xref, &obj);
+    obj = aux->fetch(xref);
   }
-  dest = createLinkDest(&obj);
-  obj.free();
-
-  return dest;
+  return createLinkDest(&obj);
 }
 
 FileSpec *Catalog::embeddedFile(int i)
@@ -565,9 +484,8 @@ FileSpec *Catalog::embeddedFile(int i)
     Object *obj = getEmbeddedFileNameTree()->getValue(i);
     FileSpec *embeddedFile = 0;
     if (obj->isRef()) {
-      Object fsDict;
-      embeddedFile = new FileSpec(obj->fetch(xref, &fsDict));
-      fsDict.free();
+      Object fsDict = obj->fetch(xref);
+      embeddedFile = new FileSpec(&fsDict);
     } else if (obj->isDict()) {
       embeddedFile = new FileSpec(obj);
     } else {
@@ -585,27 +503,21 @@ GooString *Catalog::getJS(int i)
   catalogLocker();
   Object *aux = getJSNameTree()->getValue(i);
   if (aux) {
-    aux->fetch(xref, &obj);
+    obj = aux->fetch(xref);
   }
 
   if (!obj.isDict()) {
-    obj.free();
-    return 0;
+    return nullptr;
   }
-  Object obj2;
-  if (!obj.dictLookup("S", &obj2)->isName()) {
-    obj2.free();
-    obj.free();
-    return 0;
+  Object obj2 = obj.dictLookup("S");
+  if (!obj2.isName()) {
+    return nullptr;
   }
   if (strcmp(obj2.getName(), "JavaScript")) {
-    obj2.free();
-    obj.free();
-    return 0;
+    return nullptr;
   }
-  obj2.free();
-  obj.dictLookup("JS", &obj2);
-  GooString *js = 0;
+  obj2 = obj.dictLookup("JS");
+  GooString *js = nullptr;
   if (obj2.isString()) {
     js = new GooString(obj2.getString());
   }
@@ -614,8 +526,6 @@ GooString *Catalog::getJS(int i)
     js = new GooString();
     stream->fillGooString(js);
   }
-  obj2.free();
-  obj.free();
   return js;
 }
 
@@ -624,18 +534,16 @@ Catalog::PageMode Catalog::getPageMode() {
   catalogLocker();
   if (pageMode == pageModeNull) {
 
-    Object catDict, obj;
-
     pageMode = pageModeNone;
 
-    xref->getCatalog(&catDict);
+    Object catDict = xref->getCatalog();
     if (!catDict.isDict()) {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-      catDict.free();
       return pageMode;
     }
 
-    if (catDict.dictLookup("PageMode", &obj)->isName()) {
+    Object obj = catDict.dictLookup("PageMode");
+    if (obj.isName()) {
       if (obj.isName("UseNone"))
         pageMode = pageModeNone;
       else if (obj.isName("UseOutlines"))
@@ -649,8 +557,6 @@ Catalog::PageMode Catalog::getPageMode() {
       else if (obj.isName("UseAttachments"))
         pageMode = pageModeAttach;
     }
-    obj.free();
-    catDict.free();
   }
   return pageMode;
 }
@@ -660,19 +566,17 @@ Catalog::PageLayout Catalog::getPageLayout() {
   catalogLocker();
   if (pageLayout == pageLayoutNull) {
 
-    Object catDict, obj;
-
     pageLayout = pageLayoutNone;
 
-    xref->getCatalog(&catDict);
+    Object catDict = xref->getCatalog();
     if (!catDict.isDict()) {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-      catDict.free();
       return pageLayout;
     }
 
     pageLayout = pageLayoutNone;
-    if (catDict.dictLookup("PageLayout", &obj)->isName()) {
+    Object obj = catDict.dictLookup("PageLayout");
+    if (obj.isName()) {
       if (obj.isName("SinglePage"))
         pageLayout = pageLayoutSinglePage;
       if (obj.isName("OneColumn"))
@@ -686,8 +590,6 @@ Catalog::PageLayout Catalog::getPageLayout() {
       if (obj.isName("TwoPageRight"))
         pageLayout = pageLayoutTwoPageRight;
     }
-    obj.free();
-    catDict.free();
   }
   return pageLayout;
 }
@@ -710,20 +612,19 @@ NameTree::~NameTree()
 }
 
 NameTree::Entry::Entry(Array *array, int index) {
-    if (!array->getString(index, &name) || !array->getNF(index + 1, &value)) {
-      Object aux;
-      array->get(index, &aux);
-      if (aux.isString() && array->getNF(index + 1, &value) )
-      {
-        name.append(aux.getString());
-      }
-      else
-        error(errSyntaxError, -1, "Invalid page tree");
+  if (!array->getString(index, &name)) {
+    Object aux = array->get(index);
+    if (aux.isString())
+    {
+      name.append(aux.getString());
     }
+    else
+      error(errSyntaxError, -1, "Invalid page tree");
+  }
+  value = array->getNF(index + 1);
 }
 
 NameTree::Entry::~Entry() {
-  value.free();
 }
 
 void NameTree::addEntry(Entry *entry)
@@ -758,33 +659,29 @@ void NameTree::init(XRef *xrefA, Object *tree) {
 }
 
 void NameTree::parse(Object *tree) {
-  Object names;
-  Object kids, kid;
-  int i;
-
   if (!tree->isDict())
     return;
 
   // leaf node
-  if (tree->dictLookup("Names", &names)->isArray()) {
-    for (i = 0; i < names.arrayGetLength(); i += 2) {
+  Object names = tree->dictLookup("Names");
+  if (names.isArray()) {
+    for (int i = 0; i < names.arrayGetLength(); i += 2) {
       NameTree::Entry *entry;
 
       entry = new Entry(names.getArray(), i);
       addEntry(entry);
     }
   }
-  names.free();
 
   // root or intermediate node
-  if (tree->dictLookup("Kids", &kids)->isArray()) {
-    for (i = 0; i < kids.arrayGetLength(); ++i) {
-      if (kids.arrayGet(i, &kid)->isDict())
+  Object kids = tree->dictLookup("Kids");
+  if (kids.isArray()) {
+    for (int i = 0; i < kids.arrayGetLength(); ++i) {
+      Object kid = kids.arrayGet(i);
+      if (kid.isDict())
 	parse(&kid);
-      kid.free();
     }
   }
-  kids.free();
 }
 
 int NameTree::Entry::cmp(const void *voidKey, const void *voidEntry)
@@ -795,19 +692,17 @@ int NameTree::Entry::cmp(const void *voidKey, const void *voidEntry)
   return key->cmp(&entry->name);
 }
 
-GBool NameTree::lookup(GooString *name, Object *obj)
+Object NameTree::lookup(GooString *name)
 {
   Entry **entry;
 
   entry = (Entry **) bsearch(name, entries,
 			     length, sizeof(Entry *), Entry::cmp);
   if (entry != NULL) {
-    (*entry)->value.fetch(xref, obj);
-    return gTrue;
+    return (*entry)->value.fetch(xref);
   } else {
     error(errSyntaxError, -1, "failed to look up ({0:s})", name->getCString());
-    obj->initNull();
-    return gFalse;
+    return Object(objNull);
   }
 }
 
@@ -871,32 +766,26 @@ int Catalog::getNumPages()
   catalogLocker();
   if (numPages == -1)
   {
-    Object catDict, pagesDict, obj;
-
-    xref->getCatalog(&catDict);
+    Object catDict = xref->getCatalog();
     if (!catDict.isDict()) {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-      catDict.free();
       return 0;
     }
-    catDict.dictLookup("Pages", &pagesDict);
+    Object pagesDict = catDict.dictLookup("Pages");
 
     // This should really be isDict("Pages"), but I've seen at least one
     // PDF file where the /Type entry is missing.
     if (!pagesDict.isDict()) {
       error(errSyntaxError, -1, "Top-level pages object is wrong type ({0:s})",
           pagesDict.getTypeName());
-      pagesDict.free();
-      catDict.free();
       return 0;
     }
 
-    pagesDict.dictLookup("Count", &obj);
+    Object obj = pagesDict.dictLookup("Count");
     // some PDF files actually use real numbers here ("/Count 9.0")
     if (!obj.isNum()) {
       if (pagesDict.dictIs("Page")) {
-	Object pageRootRef;
-	catDict.dictLookupNF("Pages", &pageRootRef);
+	Object pageRootRef = catDict.dictLookupNF("Pages");
 
 	error(errSyntaxError, -1, "Pages top-level is a single Page. The document is malformed, trying to recover...");
 
@@ -941,10 +830,6 @@ int Catalog::getNumPages()
       }
 
     }
-
-    catDict.free();
-    obj.free();
-    pagesDict.free();
   }
 
   return numPages;
@@ -954,21 +839,16 @@ PageLabelInfo *Catalog::getPageLabelInfo()
 {
   catalogLocker();
   if (!pageLabelInfo) {
-    Object catDict;
-    Object obj;
-
-    xref->getCatalog(&catDict);
+    Object catDict = xref->getCatalog();
     if (!catDict.isDict()) {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-      catDict.free();
-      return NULL;
+      return nullptr;
     }
 
-    if (catDict.dictLookup("PageLabels", &obj)->isDict()) {
+    Object obj = catDict.dictLookup("PageLabels");
+    if (obj.isDict()) {
       pageLabelInfo = new PageLabelInfo(&obj, getNumPages());
     }
-    obj.free();
-    catDict.free();
   }
 
   return pageLabelInfo;
@@ -978,22 +858,16 @@ StructTreeRoot *Catalog::getStructTreeRoot()
 {
   catalogLocker();
   if (!structTreeRoot) {
-    Object catalog;
-    Object root;
-
-    xref->getCatalog(&catalog);
+    Object catalog = xref->getCatalog();
     if (!catalog.isDict()) {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catalog.getTypeName());
-      catalog.free();
       return NULL;
     }
 
-    if (catalog.dictLookup("StructTreeRoot", &root)->isDict("StructTreeRoot")) {
+    Object root = catalog.dictLookup("StructTreeRoot");
+    if (root.isDict("StructTreeRoot")) {
       structTreeRoot = new StructTreeRoot(doc, root.getDict());
     }
-
-    root.free();
-    catalog.free();
   }
   return structTreeRoot;
 }
@@ -1003,41 +877,35 @@ Guint Catalog::getMarkInfo()
   if (markInfo == markInfoNull) {
     markInfo = 0;
 
-    Object catDict;
     catalogLocker();
-    xref->getCatalog(&catDict);
+    Object catDict = xref->getCatalog();
 
     if (catDict.isDict()) {
-      Object markInfoDict;
-      catDict.dictLookup("MarkInfo", &markInfoDict);
+      Object markInfoDict = catDict.dictLookup("MarkInfo");
       if (markInfoDict.isDict()) {
-        Object value;
-
-        if (markInfoDict.dictLookup("Marked", &value)->isBool() && value.getBool())
+        Object value = markInfoDict.dictLookup("Marked");
+        if (value.isBool() && value.getBool())
           markInfo |= markInfoMarked;
         else if (!value.isNull())
           error(errSyntaxError, -1, "Marked object is wrong type ({0:s})", value.getTypeName());
-        value.free();
 
-        if (markInfoDict.dictLookup("Suspects", &value)->isBool() && value.getBool())
+        value = markInfoDict.dictLookup("Suspects");
+        if (value.isBool() && value.getBool())
           markInfo |= markInfoSuspects;
         else if (!value.isNull())
           error(errSyntaxError, -1, "Suspects object is wrong type ({0:s})", value.getTypeName());
-        value.free();
 
-        if (markInfoDict.dictLookup("UserProperties", &value)->isBool() && value.getBool())
+        value = markInfoDict.dictLookup("UserProperties");
+        if (value.isBool() && value.getBool())
           markInfo |= markInfoUserProperties;
         else if (!value.isNull())
           error(errSyntaxError, -1, "UserProperties object is wrong type ({0:s})", value.getTypeName());
-        value.free();
       } else if (!markInfoDict.isNull()) {
         error(errSyntaxError, -1, "MarkInfo object is wrong type ({0:s})", markInfoDict.getTypeName());
       }
-      markInfoDict.free();
     } else {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
     }
-    catDict.free();
   }
   return markInfo;
 }
@@ -1047,16 +915,13 @@ Object *Catalog::getOutline()
   catalogLocker();
   if (outline.isNone())
   {
-     Object catDict;
-
-     xref->getCatalog(&catDict);
+     Object catDict = xref->getCatalog();
      if (catDict.isDict()) {
-       catDict.dictLookup("Outlines", &outline);
+       outline = catDict.dictLookup("Outlines");
      } else {
        error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-       outline.initNull();
+       outline.setToNull();
      }
-     catDict.free();
   }
 
   return &outline;
@@ -1067,16 +932,13 @@ Object *Catalog::getDests()
   catalogLocker();
   if (dests.isNone())
   {
-     Object catDict;
-
-     xref->getCatalog(&catDict);
+     Object catDict = xref->getCatalog();
      if (catDict.isDict()) {
-       catDict.dictLookup("Dests", &dests);
+       dests = catDict.dictLookup("Dests");
      } else {
        error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-       dests.initNull();
+       dests.setToNull();
      }
-     catDict.free();
   }
 
   return &dests;
@@ -1088,13 +950,12 @@ Catalog::FormType Catalog::getFormType()
   FormType res = NoForm;
 
   if (acroForm.isDict()) {
-    acroForm.dictLookup("XFA", &xfa);
+    xfa = acroForm.dictLookup("XFA");
     if (xfa.isStream() || xfa.isArray()) {
       res = XfaForm;
     } else {
       res = AcroForm;
     }
-    xfa.free();
   }
 
   return res;
@@ -1130,16 +991,13 @@ Object *Catalog::getNames()
 {
   if (names.isNone())
   {
-     Object catDict;
-
-     xref->getCatalog(&catDict);
+     Object catDict = xref->getCatalog();
      if (catDict.isDict()) {
-       catDict.dictLookup("Names", &names);
+       names = catDict.dictLookup("Names");
      } else {
        error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
-       names.initNull();
+       names.setToNull();
      }
-     catDict.free();
   }
 
   return &names;
@@ -1152,11 +1010,8 @@ NameTree *Catalog::getDestNameTree()
     destNameTree = new NameTree();
 
     if (getNames()->isDict()) {
-       Object obj;
-
-       getNames()->dictLookup("Dests", &obj);
+       Object obj = getNames()->dictLookup("Dests");
        destNameTree->init(xref, &obj);
-       obj.free();
     }
 
   }
@@ -1171,11 +1026,8 @@ NameTree *Catalog::getEmbeddedFileNameTree()
     embeddedFileNameTree = new NameTree();
 
     if (getNames()->isDict()) {
-       Object obj;
-
-       getNames()->dictLookup("EmbeddedFiles", &obj);
+       Object obj = getNames()->dictLookup("EmbeddedFiles");
        embeddedFileNameTree->init(xref, &obj);
-       obj.free();
     }
 
   }
@@ -1190,11 +1042,8 @@ NameTree *Catalog::getJSNameTree()
     jsNameTree = new NameTree();
 
     if (getNames()->isDict()) {
-       Object obj;
-
-       getNames()->dictLookup("JavaScript", &obj);
+       Object obj = getNames()->dictLookup("JavaScript");
        jsNameTree->init(xref, &obj);
-       obj.free();
     }
 
   }
@@ -1203,24 +1052,18 @@ NameTree *Catalog::getJSNameTree()
 }
 
 LinkAction* Catalog::getAdditionalAction(DocumentAdditionalActionsType type) {
-  Object additionalActionsObject;
-  LinkAction *linkAction = NULL;
-
-  if (additionalActions.fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
+  LinkAction *linkAction = nullptr;
+  Object additionalActionsObject = additionalActions.fetch(doc->getXRef());
+  if (additionalActionsObject.isDict()) {
     const char *key = (type == actionCloseDocument ?       "WC" :
                        type == actionSaveDocumentStart ?   "WS" :
                        type == actionSaveDocumentFinish ?  "DS" :
                        type == actionPrintDocumentStart ?  "WP" :
                        type == actionPrintDocumentFinish ? "DP" : NULL);
 
-    Object actionObject;
-
-    if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
+    Object actionObject = additionalActionsObject.dictLookup(key);
+    if (actionObject.isDict())
       linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
-    actionObject.free();
   }
-
-  additionalActionsObject.free();
-
   return linkAction;
 }
diff --git a/poppler/Catalog.h b/poppler/Catalog.h
index ed9ec756..eb324b78 100644
--- a/poppler/Catalog.h
+++ b/poppler/Catalog.h
@@ -69,7 +69,7 @@ public:
   NameTree();
   ~NameTree();
   void init(XRef *xref, Object *tree);
-  GBool lookup(GooString *name, Object *obj);
+  Object lookup(GooString *name);
   int numEntries() { return length; };
   // iterator accessor, note it returns a pointer to the internal object, do not free nor delete it
   Object *getValue(int i);
diff --git a/poppler/DCTStream.cc b/poppler/DCTStream.cc
index 6bdb0036..b3e1303f 100644
--- a/poppler/DCTStream.cc
+++ b/poppler/DCTStream.cc
@@ -64,14 +64,10 @@ DCTStream::DCTStream(Stream *strA, int colorXformA, Dict *dict, int recursion) :
   FilterStream(strA) {
   colorXform = colorXformA;
   if (dict != NULL) {
-    Object obj;
-
-    dict->lookup("Width", &obj, recursion);
+    Object obj = dict->lookup("Width", recursion);
     err.width = (obj.isInt() && obj.getInt() <= JPEG_MAX_DIMENSION) ? obj.getInt() : 0;
-    obj.free();
-    dict->lookup("Height", &obj, recursion);
+    obj = dict->lookup("Height", recursion);
     err.height = (obj.isInt() && obj.getInt() <= JPEG_MAX_DIMENSION) ? obj.getInt() : 0;
-    obj.free();
   } else
     err.height = err.width = 0;
   init();
diff --git a/poppler/Dict.cc b/poppler/Dict.cc
index cdd7d27b..5c231d14 100644
--- a/poppler/Dict.cc
+++ b/poppler/Dict.cc
@@ -98,7 +98,8 @@ Dict::Dict(Dict* dictA) {
   entries = (DictEntry *)gmallocn(size, sizeof(DictEntry));
   for (int i=0; i<length; i++) {
     entries[i].key = copyString(dictA->entries[i].key);
-    dictA->entries[i].val.copy(&entries[i].val);
+    entries[i].val.initNullAfterMalloc();
+    entries[i].val = dictA->entries[i].val.copy();
   }
 }
 
@@ -109,8 +110,7 @@ Dict *Dict::copy(XRef *xrefA) {
   for (int i=0; i<length; i++) {
     if (dictA->entries[i].val.getType() == objDict) {
        Dict *copy = dictA->entries[i].val.getDict()->copy(xrefA);
-       dictA->entries[i].val.initDict(copy);
-       copy->decRef();
+       dictA->entries[i].val = Object(copy);
     }
   }
   return dictA;
@@ -141,7 +141,7 @@ int Dict::decRef() {
   return ref;
 }
 
-void Dict::add(char *key, Object *val) {
+void Dict::add(char *key, Object &&val) {
   dictLocker();
   if (sorted) {
     // We use add on very few occasions so
@@ -158,8 +158,8 @@ void Dict::add(char *key, Object *val) {
     entries = (DictEntry *)greallocn(entries, size, sizeof(DictEntry));
   }
   entries[length].key = key;
-  entries[length].val.initNullNoFree();
-  val->shallowCopy(&entries[length].val);
+  entries[length].val.initNullAfterMalloc();
+  entries[length].val = std::move(val);
   ++length;
 }
 
@@ -167,8 +167,8 @@ inline DictEntry *Dict::find(const char *key) {
   if (!sorted && length >= SORT_LENGTH_LOWER_LIMIT)
   {
       dictLocker();
-// TODO      sorted = gTrue;
-//       std::sort(entries, entries+length, cmpDictEntries);
+      sorted = gTrue;
+      std::sort(entries, entries+length, cmpDictEntries);
   }
 
   if (sorted) {
@@ -226,24 +226,23 @@ void Dict::remove(const char *key) {
     if (i!=length) {
       //don't copy the last entry if it is deleted
       entries[i].key = entries[length].key;
-      entries[length].val.shallowCopy(&entries[i].val);
+      entries[i].val = std::move(entries[length].val);
     }
   }
 }
 
-void Dict::set(const char *key, Object *val) {
+void Dict::set(const char *key, Object &&val) {
   DictEntry *e;
-  if (val->isNull()) {
+  if (val.isNull()) {
     remove(key);
     return;
   }
   e = find (key);
   if (e) {
     dictLocker();
-    e->val.free();
-    val->shallowCopy(&e->val);
+    e->val = std::move(val);
   } else {
-    add (copyString(key), val);
+    add (copyString(key), std::move(val));
   }
 }
 
@@ -254,27 +253,25 @@ GBool Dict::is(const char *type) {
   return (e = find("Type")) && e->val.isName(type);
 }
 
-Object *Dict::lookup(const char *key, Object *obj, int recursion) {
+Object Dict::lookup(const char *key, int recursion) {
   DictEntry *e;
 
-  return (e = find(key)) ? e->val.fetch(xref, obj, recursion) : obj->initNull();
+  return (e = find(key)) ? e->val.fetch(xref, recursion) : Object(objNull);
 }
 
-Object *Dict::lookupNF(const char *key, Object *obj) {
+Object Dict::lookupNF(const char *key) {
   DictEntry *e;
 
-  return (e = find(key)) ? e->val.copy(obj) : obj->initNull();
+  return (e = find(key)) ? e->val.copy() : Object(objNull);
 }
 
 GBool Dict::lookupInt(const char *key, const char *alt_key, int *value)
 {
-  Object obj1;
   GBool success = gFalse;
-  
-  lookup ((char *) key, &obj1);
+  Object obj1 = lookup ((char *) key);
   if (obj1.isNull () && alt_key != NULL) {
     obj1.free ();
-    lookup ((char *) alt_key, &obj1);
+    obj1 = lookup ((char *) alt_key);
   }
   if (obj1.isInt ()) {
     *value = obj1.getInt ();
@@ -290,10 +287,10 @@ char *Dict::getKey(int i) {
   return entries[i].key;
 }
 
-Object *Dict::getVal(int i, Object *obj) {
-  return entries[i].val.fetch(xref, obj);
+Object Dict::getVal(int i) {
+  return entries[i].val.fetch(xref);
 }
 
-Object *Dict::getValNF(int i, Object *obj) {
-  return entries[i].val.copy(obj);
+Object Dict::getValNF(int i) {
+  return entries[i].val.copy();
 }
diff --git a/poppler/Dict.h b/poppler/Dict.h
index c6b43e40..0e65bfed 100644
--- a/poppler/Dict.h
+++ b/poppler/Dict.h
@@ -65,11 +65,11 @@ public:
 
   // Add an entry.  NB: does not copy key.
   // val becomes a dead object after the call
-  void add(char *key, Object *val);
+  void add(char *key, Object &&val);
 
   // Update the value of an existing entry, otherwise create it
   // val becomes a dead object after the call
-  void set(const char *key, Object *val);
+  void set(const char *key, Object &&val);
   // Remove an entry. This invalidate indexes
   void remove(const char *key);
 
@@ -78,14 +78,14 @@ public:
 
   // Look up an entry and return the value.  Returns a null object
   // if <key> is not in the dictionary.
-  Object *lookup(const char *key, Object *obj, int recursion = 0);
-  Object *lookupNF(const char *key, Object *obj);
+  Object lookup(const char *key, int recursion = 0);
+  Object lookupNF(const char *key);
   GBool lookupInt(const char *key, const char *alt_key, int *value);
 
   // Iterative accessors.
   char *getKey(int i);
-  Object *getVal(int i, Object *obj);
-  Object *getValNF(int i, Object *obj);
+  Object getVal(int i);
+  Object getValNF(int i);
 
   // Set the xref pointer.  This is only used in one special case: the
   // trailer dictionary, which is read before the xref table is
diff --git a/poppler/FileSpec.cc b/poppler/FileSpec.cc
index bac1eaea..cb7392a5 100644
--- a/poppler/FileSpec.cc
+++ b/poppler/FileSpec.cc
@@ -35,40 +35,37 @@ EmbFile::EmbFile(Object *efStream)
   m_checksum = NULL;
   m_mimetype = NULL;
 
-  efStream->copy(&m_objStr);
+  m_objStr = efStream->copy();
 
   if (efStream->isStream()) {
     // dataDict corresponds to Table 3.41 in the PDF1.6 spec.
     Dict *dataDict = efStream->streamGetDict();
 
     // subtype is normally the mimetype
-    Object subtypeName;
-    if (dataDict->lookup("Subtype", &subtypeName)->isName()) {
+    Object subtypeName = dataDict->lookup("Subtype");
+    if (subtypeName.isName()) {
       m_mimetype = new GooString(subtypeName.getName());
     }
-    subtypeName.free();
 
     // paramDict corresponds to Table 3.42 in the PDF1.6 spec
-    Object paramDict;
-    if (dataDict->lookup("Params", &paramDict)->isDict()) {
-      Object paramObj;
-      if (paramDict.dictLookup("ModDate", &paramObj)->isString())
+    Object paramDict = dataDict->lookup("Params");
+    if (paramDict.isDict()) {
+      Object paramObj = paramDict.dictLookup("ModDate");
+      if (paramObj.isString())
         m_modDate = new GooString(paramObj.getString());
-      paramObj.free();
 
-      if (paramDict.dictLookup("CreationDate", &paramObj)->isString())
+      paramObj = paramDict.dictLookup("CreationDate");
+      if (paramObj.isString())
         m_createDate = new GooString(paramObj.getString());
-      paramObj.free();
 
-      if (paramDict.dictLookup("Size", &paramObj)->isInt())
+      paramObj = paramDict.dictLookup("Size");
+      if (paramObj.isInt())
         m_size = paramObj.getInt();
-      paramObj.free();
 
-      if (paramDict.dictLookup("CheckSum", &paramObj)->isString())
+      paramObj = paramDict.dictLookup("CheckSum");
+      if (paramObj.isString())
         m_checksum = new GooString(paramObj.getString());
-      paramObj.free();
     }
-    paramDict.free();
   }
 }
 
@@ -78,7 +75,6 @@ EmbFile::~EmbFile()
   delete m_modDate;
   delete m_checksum;
   delete m_mimetype;
-  m_objStr.free();
 }
 
 GBool EmbFile::save(const char *path) {
@@ -110,41 +106,37 @@ FileSpec::FileSpec(Object *fileSpecA)
   platformFileName = NULL;
   embFile = NULL;
   desc = NULL;
-  fileSpecA->copy(&fileSpec);
+  fileSpec = fileSpecA->copy();
 
-  Object obj1;
-  if (!getFileSpecName(fileSpecA, &obj1)) {
+  Object obj1 = getFileSpecName(fileSpecA);
+  if (!obj1.isString()) {
     ok = gFalse;
-    obj1.free();
     error(errSyntaxError, -1, "Invalid FileSpec");
     return;
   }
 
   fileName = obj1.getString()->copy();
-  obj1.free();
 
   if (fileSpec.isDict()) {
-    if (fileSpec.dictLookup("EF", &obj1)->isDict()) {
-      if (!obj1.dictLookupNF("F", &fileStream)->isRef()) {
+    obj1 = fileSpec.dictLookup("EF");
+    if (obj1.isDict()) {
+      fileStream = obj1.dictLookupNF("F");
+      if (!fileStream.isRef()) {
         ok = gFalse;
-        fileStream.free();
+        fileStream.setToNull();
         error(errSyntaxError, -1, "Invalid FileSpec: Embedded file stream is not an indirect reference");
-        obj1.free();
         return;
       }
     }
-    obj1.free();
   }
 
-  if (fileSpec.dictLookup("Desc", &obj1)->isString())
+  obj1 = fileSpec.dictLookup("Desc");
+  if (obj1.isString())
     desc = obj1.getString()->copy();
-  obj1.free();
 }
 
 FileSpec::~FileSpec()
 {
-  fileSpec.free();
-  fileStream.free();
   delete fileName;
   delete platformFileName;
   delete embFile;
@@ -161,8 +153,8 @@ EmbFile *FileSpec::getEmbeddedFile()
 
   Object obj1;
   XRef *xref = fileSpec.getDict()->getXRef();
-  embFile = new EmbFile(fileStream.fetch(xref, &obj1));
-  obj1.free();
+  obj1 = fileStream.fetch(xref);
+  embFile = new EmbFile(&obj1);
 
   return embFile;
 }
@@ -172,84 +164,77 @@ GooString *FileSpec::getFileNameForPlatform()
   if (platformFileName)
     return platformFileName;
 
-  Object obj1;
-  if (getFileSpecNameForPlatform(&fileSpec, &obj1))
+  Object obj1 = getFileSpecNameForPlatform(&fileSpec);
+  if (obj1.isString())
     platformFileName = obj1.getString()->copy();
-  obj1.free();
 
   return platformFileName;
 }
 
-GBool getFileSpecName (Object *fileSpec, Object *fileName)
+Object getFileSpecName (Object *fileSpec)
 {
   if (fileSpec->isString()) {
-    fileSpec->copy(fileName);
-    return gTrue;
+    return fileSpec->copy();
   }
   
   if (fileSpec->isDict()) {
-    fileSpec->dictLookup("UF", fileName);
-    if (fileName->isString()) {
-      return gTrue;
+    Object fileName = fileSpec->dictLookup("UF");
+    if (fileName.isString()) {
+      return fileName;
     }
-    fileName->free();
-    fileSpec->dictLookup("F", fileName);
-    if (fileName->isString()) {
-      return gTrue;
+    fileName = fileSpec->dictLookup("F");
+    if (fileName.isString()) {
+      return fileName;
     }
-    fileName->free();
-    fileSpec->dictLookup("DOS", fileName);
-    if (fileName->isString()) {
-      return gTrue;
+    fileName = fileSpec->dictLookup("DOS");
+    if (fileName.isString()) {
+      return fileName;
     }
-    fileName->free();
-    fileSpec->dictLookup("Mac", fileName);
-    if (fileName->isString()) {
-      return gTrue;
+    fileName = fileSpec->dictLookup("Mac");
+    if (fileName.isString()) {
+      return fileName;
     }
-    fileName->free();
-    fileSpec->dictLookup("Unix", fileName);
-    if (fileName->isString()) {
-      return gTrue;
+    fileName = fileSpec->dictLookup("Unix");
+    if (fileName.isString()) {
+      return fileName;
     }
-    fileName->free();
   }
-  return gFalse;
+  return Object();
 }
 
-GBool getFileSpecNameForPlatform (Object *fileSpec, Object *fileName)
+Object getFileSpecNameForPlatform (Object *fileSpec)
 {
   if (fileSpec->isString()) {
-    fileSpec->copy(fileName);
-    return gTrue;
+    return fileSpec->copy();
   }
 
+  Object fileName;
   if (fileSpec->isDict()) {
-    if (!fileSpec->dictLookup("UF", fileName)->isString ()) {
-      fileName->free();
-      if (!fileSpec->dictLookup("F", fileName)->isString ()) {
-        fileName->free();
+    fileName = fileSpec->dictLookup("UF");
+    if (!fileName.isString ()) {
+      fileName = fileSpec->dictLookup("F");
+      if (!fileName.isString ()) {
 #ifdef _WIN32
 	const char *platform = "DOS";
 #else
 	const char *platform = "Unix";
 #endif
-	if (!fileSpec->dictLookup(platform, fileName)->isString ()) {
-	  fileName->free();
+        fileName = fileSpec->dictLookup(platform);
+	if (!fileName.isString ()) {
 	  error(errSyntaxError, -1, "Illegal file spec");
-	  return gFalse;
+	  return Object();
 	}
       }
     }
   } else {
     error(errSyntaxError, -1, "Illegal file spec");
-    return gFalse;
+    return Object();
   }
 
   // system-dependent path manipulation
 #ifdef _WIN32
   int i, j;
-  GooString *name = fileName->getString();
+  GooString *name = fileName.getString();
   // "//...."             --> "\...."
   // "/x/...."            --> "x:\...."
   // "/server/share/...." --> "\\server\share\...."
@@ -291,5 +276,5 @@ GBool getFileSpecNameForPlatform (Object *fileSpec, Object *fileName)
   }
 #endif /* _WIN32 */
 
-  return gTrue;
+  return fileName;
 }
diff --git a/poppler/FileSpec.h b/poppler/FileSpec.h
index 9f2f6fcd..233401f1 100644
--- a/poppler/FileSpec.h
+++ b/poppler/FileSpec.h
@@ -70,7 +70,7 @@ private:
   GooString *desc;             // Desc
 };
 
-GBool getFileSpecName (Object *fileSpec, Object *fileName);
-GBool getFileSpecNameForPlatform (Object *fileSpec, Object *fileName);
+Object getFileSpecName (Object *fileSpec);
+Object getFileSpecNameForPlatform (Object *fileSpec);
 
 #endif /* FILE_SPEC_H */
diff --git a/poppler/FontInfo.cc b/poppler/FontInfo.cc
index 8fc89e9d..523849de 100644
--- a/poppler/FontInfo.cc
+++ b/poppler/FontInfo.cc
@@ -54,7 +54,6 @@ GooList *FontInfoScanner::scan(int nPages) {
   Page *page;
   Dict *resDict;
   Annots *annots;
-  Object obj1;
   int lastPage;
 
   if (currentPage > doc->getNumPages()) {
@@ -79,10 +78,10 @@ GooList *FontInfoScanner::scan(int nPages) {
     }
     annots = page->getAnnots();
     for (int i = 0; i < annots->getNumAnnots(); ++i) {
-      if (annots->getAnnot(i)->getAppearanceResDict(&obj1)->isDict()) {
+      Object obj1 = annots->getAnnot(i)->getAppearanceResDict();
+      if (obj1.isDict()) {
         scanFonts(xrefA, obj1.getDict(), result);
       }
-      obj1.free();
     }
   }
 
@@ -93,27 +92,24 @@ GooList *FontInfoScanner::scan(int nPages) {
 }
 
 void FontInfoScanner::scanFonts(XRef *xrefA, Dict *resDict, GooList *fontsList) {
-  Object obj1, obj2, objDict, resObj;
   Ref r;
   GfxFontDict *gfxFontDict;
   GfxFont *font;
-  int i;
 
   // scan the fonts in this resource dictionary
   gfxFontDict = NULL;
-  resDict->lookupNF("Font", &obj1);
+  Object obj1 = resDict->lookupNF("Font");
   if (obj1.isRef()) {
-    obj1.fetch(xrefA, &obj2);
+    Object obj2 = obj1.fetch(xrefA);
     if (obj2.isDict()) {
       r = obj1.getRef();
       gfxFontDict = new GfxFontDict(xrefA, &r, obj2.getDict());
     }
-    obj2.free();
   } else if (obj1.isDict()) {
     gfxFontDict = new GfxFontDict(xrefA, NULL, obj1.getDict());
   }
   if (gfxFontDict) {
-    for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
+    for (int i = 0; i < gfxFontDict->getNumFonts(); ++i) {
       if ((font = gfxFontDict->getFont(i))) {
         Ref fontRef = *font->getID();
 
@@ -126,48 +122,39 @@ void FontInfoScanner::scanFonts(XRef *xrefA, Dict *resDict, GooList *fontsList)
     }
     delete gfxFontDict;
   }
-  obj1.free();
 
   // recursively scan any resource dictionaries in objects in this
   // resource dictionary
   const char *resTypes[] = { "XObject", "Pattern" };
   for (Guint resType = 0; resType < sizeof(resTypes) / sizeof(resTypes[0]); ++resType) {
-    resDict->lookup(resTypes[resType], &objDict);
+    Object objDict = resDict->lookup(resTypes[resType]);
     if (objDict.isDict()) {
-      for (i = 0; i < objDict.dictGetLength(); ++i) {
-        objDict.dictGetValNF(i, &obj1);
+      for (int i = 0; i < objDict.dictGetLength(); ++i) {
+        obj1 = objDict.dictGetValNF(i);
         if (obj1.isRef()) {
           // check for an already-seen object
           const Ref r = obj1.getRef();
           if (visitedObjects.find(r.num) != visitedObjects.end()) {
-            obj1.free();
             continue;
           }
 
           visitedObjects.insert(r.num);
         }
 
-        obj1.fetch(xrefA, &obj2);
-
+        Object obj2 = obj1.fetch(xrefA);
         if (obj2.isStream()) {
-          obj2.streamGetDict()->lookup("Resources", &resObj);
+          Object resObj = obj2.streamGetDict()->lookup("Resources");
           if (resObj.isDict() && resObj.getDict() != resDict) {
             scanFonts(xrefA, resObj.getDict(), fontsList);
           }
-          resObj.free();
         }
-        obj1.free();
-        obj2.free();
       }
     }
-    objDict.free();
   }
 }
 
 FontInfo::FontInfo(GfxFont *font, XRef *xref) {
   GooString *origName;
-  Object fontObj, toUnicodeObj;
-  int i;
 
   fontRef = *font->getID();
 
@@ -204,16 +191,16 @@ FontInfo::FontInfo(GfxFont *font, XRef *xref) {
 
   // look for a ToUnicode map
   hasToUnicode = gFalse;
-  if (xref->fetch(fontRef.num, fontRef.gen, &fontObj)->isDict()) {
-    hasToUnicode = fontObj.dictLookup("ToUnicode", &toUnicodeObj)->isStream();
-    toUnicodeObj.free();
+  Object fontObj = xref->fetch(fontRef.num, fontRef.gen);
+  if (fontObj.isDict()) {
+    hasToUnicode = fontObj.dictLookup("ToUnicode").isStream();
   }
-  fontObj.free();
 
   // check for a font subset name: capital letters followed by a '+'
   // sign
   subset = gFalse;
   if (name) {
+    int i;
     for (i = 0; i < name->getLength(); ++i) {
       if (name->getChar(i) < 'A' || name->getChar(i) > 'Z') {
 	break;
diff --git a/poppler/Form.cc b/poppler/Form.cc
index e4a20dd0..c7da7532 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -85,7 +85,7 @@ FormWidget::FormWidget(PDFDoc *docA, Object *aobj, unsigned num, Ref aref, FormF
   childNum = num;
   doc = docA;
   xref = doc->getXRef();
-  aobj->copy(&obj);
+  obj = aobj->copy();
   type = formUndef;
   field = fieldA;
   widget = NULL;
@@ -95,7 +95,6 @@ FormWidget::~FormWidget()
 {
   if (widget)
     widget->decRefCnt();
-  obj.free ();
 }
 
 #ifdef DEBUG_FORMS
@@ -108,10 +107,8 @@ void FormWidget::createWidgetAnnotation() {
   if (widget)
     return;
 
-  Object obj1;
-  obj1.initRef(ref.num, ref.gen);
+  Object obj1(ref.num, ref.gen);
   widget = new AnnotWidget(doc, obj.getDict(), &obj1, field);
-  obj1.free();
 }
 
 GBool FormWidget::inRect(double x, double y) const {
@@ -178,13 +175,13 @@ FormWidgetButton::FormWidgetButton (PDFDoc *docA, Object *aobj, unsigned num, Re
   type = formButton;
   onStr = NULL;
 
-  Object obj1, obj2;
-
   // Find the name of the ON state in the AP dictionnary
   // The reference say the Off state, if it existe, _must_ be stored in the AP dict under the name /Off
   // The "on" state may be stored under any other name
-  if (obj.dictLookup("AP", &obj1)->isDict()) {
-    if (obj1.dictLookup("N", &obj2)->isDict()) {
+  Object obj1 = obj.dictLookup("AP");
+  if (obj1.isDict()) {
+    Object obj2 = obj1.dictLookup("N");
+    if (obj2.isDict()) {
       for (int i = 0; i < obj2.dictGetLength(); i++) {
         char *key = obj2.dictGetKey(i);
         if (strcmp (key, "Off") != 0) {
@@ -193,9 +190,7 @@ FormWidgetButton::FormWidgetButton (PDFDoc *docA, Object *aobj, unsigned num, Re
         }
       }
     }
-    obj2.free();
   }
-  obj1.free();
 }
 
 char *FormWidgetButton::getOnStr() {
@@ -462,7 +457,7 @@ FormField::FormField(PDFDoc *docA, Object *aobj, const Ref& aref, FormField *par
 {
   doc = docA;
   xref = doc->getXRef();
-  aobj->copy(&obj);
+  obj = aobj->copy();
   Dict* dict = obj.getDict();
   ref.num = ref.gen = 0;
   type = ty;
@@ -479,76 +474,65 @@ FormField::FormField(PDFDoc *docA, Object *aobj, const Ref& aref, FormField *par
 
   ref = aref;
 
-  Object obj1;
   //childs
-  if (dict->lookup("Kids", &obj1)->isArray()) {
+  Object obj1 = dict->lookup("Kids");
+  if (obj1.isArray()) {
     // Load children
     for (int i = 0 ; i < obj1.arrayGetLength(); i++) {
-      Object childRef, childObj;
-
-      if (!obj1.arrayGetNF(i, &childRef)->isRef()) {
+      Object childRef = obj1.arrayGetNF(i);
+      if (!childRef.isRef()) {
         error (errSyntaxError, -1, "Invalid form field renference");
-        childRef.free();
         continue;
       }
-      if (!obj1.arrayGet(i, &childObj)->isDict()) {
+      Object childObj = obj1.arrayGet(i);
+      if (!childObj.isDict()) {
         error (errSyntaxError, -1, "Form field child is not a dictionary");
-        childObj.free();
-        childRef.free();
         continue;
       }
 
       const Ref ref = childRef.getRef();
       if (usedParents->find(ref.num) == usedParents->end()) {
-        Object obj2, obj3;
         // Field child: it could be a form field or a widget or composed dict
-        if (childObj.dictLookupNF("Parent", &obj2)->isRef() || childObj.dictLookup("Parent", &obj3)->isDict()) {
+        Object obj2 = childObj.dictLookupNF("Parent");
+	Object obj3 = childObj.dictLookup("Parent");
+        if (obj2.isRef() || obj3.isDict()) {
           // Child is a form field or composed dict
           // We create the field, if it's composed
           // it will create the widget as a child
           std::set<int> usedParentsAux = *usedParents;
           usedParentsAux.insert(ref.num);
-          obj2.free();
-          obj3.free();
 
           if (terminal) {
             error(errSyntaxWarning, -1, "Field can't have both Widget AND Field as kids\n");
-            childObj.free();
-            childRef.free();
             continue;
           }
 
           numChildren++;
           children = (FormField**)greallocn(children, numChildren, sizeof(FormField*));
           children[numChildren - 1] = Form::createFieldFromDict(&childObj, doc, ref, this, &usedParentsAux);
-        } else if (childObj.dictLookup("Subtype", &obj2)->isName("Widget")) {
-          // Child is a widget annotation
-          if (!terminal && numChildren > 0) {
-            error(errSyntaxWarning, -1, "Field can't have both Widget AND Field as kids\n");
-            obj2.free();
-            obj3.free();
-            childObj.free();
-            childRef.free();
-            continue;
-          }
-          _createWidget(&childObj, ref);
-        }
-        obj2.free();
-        obj3.free();
+        } else {
+	  obj2 = childObj.dictLookup("Subtype");
+	  if (obj2.isName("Widget")) {
+	    // Child is a widget annotation
+	    if (!terminal && numChildren > 0) {
+	      error(errSyntaxWarning, -1, "Field can't have both Widget AND Field as kids\n");
+	      continue;
+	    }
+	    _createWidget(&childObj, ref);
+	  }
+	}
       }
-      childObj.free();
-      childRef.free();
     }
   } else {
     // No children, if it's a composed dict, create the child widget
-    obj1.free();
-    if (dict->lookup("Subtype", &obj1)->isName("Widget"))
+    obj1 = dict->lookup("Subtype");
+    if (obj1.isName("Widget"))
       _createWidget(&obj, ref);
   }
-  obj1.free();
 
   //flags
-  if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
+  obj1 = Form::fieldLookup(dict, "Ff");
+  if (obj1.isInt()) {
     int flags = obj1.getInt();
     if (flags & 0x1) { // 1 -> ReadOnly
       readOnly = true;
@@ -560,39 +544,38 @@ FormField::FormField(PDFDoc *docA, Object *aobj, const Ref& aref, FormField *par
       //TODO
     }
   }
-  obj1.free();
 
   // Variable Text
-  if (Form::fieldLookup(dict, "DA", &obj1)->isString())
+  obj1 = Form::fieldLookup(dict, "DA");
+  if (obj1.isString())
     defaultAppearance = obj1.getString()->copy();
-  obj1.free();
 
-  if (Form::fieldLookup(dict, "Q", &obj1)->isInt()) {
+  obj1 = Form::fieldLookup(dict, "Q");
+  if (obj1.isInt()) {
     quadding = static_cast<VariableTextQuadding>(obj1.getInt());
     hasQuadding = gTrue;
   }
-  obj1.free();
 
-  if (dict->lookup("T", &obj1)->isString()) {
+  obj1 = dict->lookup("T");
+  if (obj1.isString()) {
     partialName = obj1.getString()->copy();
   } else {
     partialName = NULL;
   }
-  obj1.free();
 
-  if (dict->lookup("TU", &obj1)->isString()) {
+  obj1 = dict->lookup("TU");
+  if (obj1.isString()) {
     alternateUiName = obj1.getString()->copy();
   } else {
     alternateUiName = NULL;
   }
-  obj1.free();
 
-  if(dict->lookup("TM", &obj1)->isString()) {
+  obj1 = dict->lookup("TM");
+  if(obj1.isString()) {
     mappingName = obj1.getString()->copy();
   } else {
     mappingName = NULL;
   }
-  obj1.free();
 }
 
 void FormField::setPartialName(const GooString &name)
@@ -600,9 +583,7 @@ void FormField::setPartialName(const GooString &name)
   delete partialName;
   partialName = name.copy();
 
-  Object obj1;
-  obj1.initString(name.copy());
-  obj.getDict()->set("T", &obj1);
+  obj.getDict()->set("T", Object(name.copy()));
   xref->setModifiedObject(&obj, ref);
 }
 
@@ -619,7 +600,6 @@ FormField::~FormField()
       delete widgets[i];
     gfree (widgets);
   }
-  obj.free();
 
   delete defaultAppearance;
   delete partialName;
@@ -710,7 +690,7 @@ FormWidget* FormField::findWidgetByRef (Ref aref)
 }
 
 GooString* FormField::getFullyQualifiedName() {
-  Object obj1, obj2;
+  Object obj1;
   Object parent;
   GooString *parent_name;
   GooString *full_name;
@@ -721,9 +701,10 @@ GooString* FormField::getFullyQualifiedName() {
 
   full_name = new GooString();
 
-  obj.copy(&obj1);
-  while (obj1.dictLookup("Parent", &parent)->isDict()) {
-    if (parent.dictLookup("T", &obj2)->isString()) {
+  obj1 = obj.copy();
+  while (parent = obj1.dictLookup("Parent"), parent.isDict()) {
+    Object obj2 = parent.dictLookup("T");
+    if (obj2.isString()) {
       parent_name = obj2.getString();
 
       if (unicode_encoded) {
@@ -746,14 +727,9 @@ GooString* FormField::getFullyQualifiedName() {
           full_name->insert(0, parent_name);
         }
       }
-      obj2.free();
     }
-    obj1.free();
-    parent.copy(&obj1);
-    parent.free();
+    obj1 = parent.copy();
   }
-  obj1.free();
-  parent.free();
 
   if (partialName) {
     if (unicode_encoded) {
@@ -820,11 +796,11 @@ FormFieldButton::FormFieldButton(PDFDoc *docA, Object *aobj, const Ref& ref, For
   noAllOff = false;
   siblings = NULL;
   numSiblings = 0;
-  appearanceState.initNull();
+  appearanceState.setToNull();
 
-  Object obj1;
-  btype = formButtonCheck; 
-  if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
+  btype = formButtonCheck;
+  Object obj1 = Form::fieldLookup(dict, "Ff");
+  if (obj1.isInt()) {
     int flags = obj1.getInt();
     
     if (flags & 0x10000) { // 17 -> push button
@@ -843,7 +819,7 @@ FormFieldButton::FormFieldButton(PDFDoc *docA, Object *aobj, const Ref& ref, For
   if (btype != formButtonPush) {
     // Even though V is inheritable we are interested in the value of this
     // field, if not present it's probably because it's a button in a set.
-    dict->lookup("V", &appearanceState);
+    appearanceState = dict->lookup("V");
   }
 }
 
@@ -972,19 +948,13 @@ GBool FormFieldButton::getState(char *state) {
 }
 
 void FormFieldButton::updateState(char *state) {
-  Object obj1;
-
-  appearanceState.free();
-  appearanceState.initName(state);
-
-  appearanceState.copy(&obj1);
-  obj.getDict()->set("V", &obj1);
+  appearanceState = Object(objName, state);
+  obj.getDict()->set("V", appearanceState.copy());
   xref->setModifiedObject(&obj, ref);
 }
 
 FormFieldButton::~FormFieldButton()
 {
-  appearanceState.free();
   if (siblings)
     gfree(siblings);
 }
@@ -1001,7 +971,8 @@ FormFieldText::FormFieldText(PDFDoc *docA, Object *aobj, const Ref& ref, FormFie
   multiline = password = fileSelect = doNotSpellCheck = doNotScroll = comb = richText = false;
   maxLen = 0;
 
-  if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
+  obj1 = Form::fieldLookup(dict, "Ff");
+  if (obj1.isInt()) {
     int flags = obj1.getInt();
     if (flags & 0x1000) // 13 -> Multiline
       multiline = true;
@@ -1018,14 +989,14 @@ FormFieldText::FormFieldText(PDFDoc *docA, Object *aobj, const Ref& ref, FormFie
     if (flags & 0x2000000)// 26 -> RichText
       richText = true;
   }
-  obj1.free();
 
-  if (Form::fieldLookup(dict, "MaxLen", &obj1)->isInt()) {
+  obj1 = Form::fieldLookup(dict, "MaxLen");
+  if (obj1.isInt()) {
     maxLen = obj1.getInt();
   }
-  obj1.free();
 
-  if (Form::fieldLookup(dict, "V", &obj1)->isString()) {
+  obj1 = Form::fieldLookup(dict, "V");
+  if (obj1.isString()) {
     if (obj1.getString()->hasUnicodeMarker()) {
       if (obj1.getString()->getLength() > 2)
         content = obj1.getString()->copy();
@@ -1037,7 +1008,6 @@ FormFieldText::FormFieldText(PDFDoc *docA, Object *aobj, const Ref& ref, FormFie
       delete [] tmp_str;
     }
   }
-  obj1.free();
 }
 
 #ifdef DEBUG_FORMS
@@ -1069,9 +1039,7 @@ void FormFieldText::setContentCopy (GooString* new_content)
     }
   }
 
-  Object obj1;
-  obj1.initString(content ? content->copy() : new GooString(""));
-  obj.getDict()->set("V", &obj1);
+  obj.getDict()->set("V", Object(content ? content->copy() : new GooString("")));
   xref->setModifiedObject(&obj, ref);
   updateChildrenAppearance();
 }
@@ -1098,7 +1066,8 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For
 
   combo = edit = multiselect = doNotSpellCheck = doCommitOnSelChange = false;
 
-  if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
+  obj1 = Form::fieldLookup(dict, "Ff");
+  if (obj1.isInt()) {
     int flags = obj1.getInt();
     if (flags & 0x20000) // 18 -> Combo
       combo = true; 
@@ -1111,67 +1080,62 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For
     if (flags & 0x4000000) // 27 -> CommitOnSelChange
       doCommitOnSelChange = true;
   }
-  obj1.free();
 
-  if (dict->lookup("TI", &obj1)->isInt())
+  obj1 = dict->lookup("TI");
+  if (obj1.isInt())
     topIdx = obj1.getInt();
-  obj1.free();
-
-  if (dict->lookup("Opt", &obj1)->isArray()) {
-    Object obj2;
 
+  obj1 = dict->lookup("Opt");
+  if (obj1.isArray()) {
     numChoices = obj1.arrayGetLength();
     choices = new ChoiceOpt[numChoices];
     memset(choices, 0, sizeof(ChoiceOpt) * numChoices);
 
     for (int i = 0; i < numChoices; i++) {
-      if (obj1.arrayGet(i, &obj2)->isString()) {
+      Object obj2 = obj1.arrayGet(i);
+      if (obj2.isString()) {
         choices[i].optionName = obj2.getString()->copy();
       } else if (obj2.isArray()) { // [Export_value, Displayed_text]
-        Object obj3;
-
         if (obj2.arrayGetLength() < 2) {
           error(errSyntaxError, -1, "FormWidgetChoice:: invalid Opt entry -- array's length < 2\n");
           continue;
         }
-        if (obj2.arrayGet(0, &obj3)->isString())
+        Object obj3 = obj2.arrayGet(0);
+        if (obj3.isString())
           choices[i].exportVal = obj3.getString()->copy();
         else
           error(errSyntaxError, -1, "FormWidgetChoice:: invalid Opt entry -- exported value not a string\n");
-        obj3.free();
 
-        if (obj2.arrayGet(1, &obj3)->isString())
+        obj3 = obj2.arrayGet(1);
+        if (obj3.isString())
           choices[i].optionName = obj3.getString()->copy();
         else
           error(errSyntaxError, -1, "FormWidgetChoice:: invalid Opt entry -- choice name not a string\n");
-        obj3.free();
       } else {
         error(errSyntaxError, -1, "FormWidgetChoice:: invalid {0:d} Opt entry\n", i);
       }
-      obj2.free();
     }
   } else {
     //empty choice
   }
-  obj1.free();
 
   // Find selected items
   // Note: PDF specs say that /V has precedence over /I, but acroread seems to
   // do the opposite. We do the same.
-  if (Form::fieldLookup(dict, "I", &obj1)->isArray()) {
+  obj1 = Form::fieldLookup(dict, "I");
+  if (obj1.isArray()) {
     for (int i = 0; i < obj1.arrayGetLength(); i++) {
-      Object obj2;
-      if (obj1.arrayGet(i, &obj2)->isInt() && obj2.getInt() >= 0 && obj2.getInt() < numChoices) {
+      Object obj2 = obj1.arrayGet(i);
+      if (obj2.isInt() && obj2.getInt() >= 0 && obj2.getInt() < numChoices) {
         choices[obj2.getInt()].selected = true;
       }
-      obj2.free();
     }
   } else {
-    obj1.free();
     // Note: According to PDF specs, /V should *never* contain the exportVal.
     // However, if /Opt is an array of (exportVal,optionName) pairs, acroread
     // seems to expect the exportVal instead of the optionName and so we do too.
-    if (Form::fieldLookup(dict, "V", &obj1)->isString()) {
+    obj1 = Form::fieldLookup(dict, "V");
+    if (obj1.isString()) {
       GBool optionFound = gFalse;
 
       for (int i = 0; i < numChoices; i++) {
@@ -1198,8 +1162,7 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For
     } else if (obj1.isArray()) {
       for (int i = 0; i < numChoices; i++) {
         for (int j = 0; j < obj1.arrayGetLength(); j++) {
-          Object obj2;
-          obj1.arrayGet(j, &obj2);
+          Object obj2 = obj1.arrayGet(j);
           GBool matches = gFalse;
 
           if (choices[i].exportVal) {
@@ -1212,8 +1175,6 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For
             }
           }
 
-          obj2.free();
-
           if (matches) {
             choices[i].selected = true;
             break; // We've determined that this option is selected. No need to keep on scanning
@@ -1222,7 +1183,6 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For
       }
     }
   }
-  obj1.free();
 }
 
 FormFieldChoice::~FormFieldChoice()
@@ -1244,35 +1204,35 @@ void FormFieldChoice::print(int indent)
 #endif
 
 void FormFieldChoice::updateSelection() {
-  Object objV, objI, obj1;
-  objI.initNull();
+  Object objV, obj1;
+  Object objI(objNull);
 
   if (edit && editedChoice) {
     // This is an editable combo-box with user-entered text
-    objV.initString(editedChoice->copy());
+    objV = Object(editedChoice->copy());
   } else {
     const int numSelected = getNumSelected();
 
     // Create /I array only if multiple selection is allowed (as per PDF spec)
     if (multiselect) {
-      objI.initArray(xref);
+      objI = Object(new Array(xref));
     }
 
     if (numSelected == 0) {
       // No options are selected
-      objV.initString(new GooString(""));
+      objV = Object(new GooString(""));
     } else if (numSelected == 1) {
       // Only one option is selected
       for (int i = 0; i < numChoices; i++) {
         if (choices[i].selected) {
           if (multiselect) {
-            objI.arrayAdd(obj1.initInt(i));
+            objI.arrayAdd(Object(i));
           }
 
           if (choices[i].exportVal) {
-            objV.initString(choices[i].exportVal->copy());
+            objV = Object(choices[i].exportVal->copy());
           } else if (choices[i].optionName) {
-            objV.initString(choices[i].optionName->copy());
+            objV = Object(choices[i].optionName->copy());
           }
 
           break; // We've just written the selected option. No need to keep on scanning
@@ -1280,25 +1240,25 @@ void FormFieldChoice::updateSelection() {
       }
     } else {
       // More than one option is selected
-      objV.initArray(xref);
+      objV = Object(new Array(xref));
       for (int i = 0; i < numChoices; i++) {
         if (choices[i].selected) {
           if (multiselect) {
-            objI.arrayAdd(obj1.initInt(i));
+            objI.arrayAdd(Object(i));
           }
 
           if (choices[i].exportVal) {
-            objV.arrayAdd(obj1.initString(choices[i].exportVal->copy()));
+            objV.arrayAdd(Object(choices[i].exportVal->copy()));
           } else if (choices[i].optionName) {
-            objV.arrayAdd(obj1.initString(choices[i].optionName->copy()));
+            objV.arrayAdd(Object(choices[i].optionName->copy()));
           }
         }
       }
     }
   }
 
-  obj.getDict()->set("V", &objV);
-  obj.getDict()->set("I", &objI);
+  obj.getDict()->set("V", std::move(objV));
+  obj.getDict()->set("I", std::move(objI));
   xref->setModifiedObject(&obj, ref);
   updateChildrenAppearance();
 }
@@ -1399,7 +1359,6 @@ FormFieldSignature::FormFieldSignature(PDFDoc *docA, Object *dict, const Ref& re
 
 FormFieldSignature::~FormFieldSignature()
 {
-  byte_range.free();
   delete signature_info;
   delete signature;
 }
@@ -1409,39 +1368,31 @@ void FormFieldSignature::parseInfo()
   if (!obj.isDict())
     return;
 
-  Object sig_dict, contents_obj, time_of_signing, subfilterName;
-
   // retrieve PKCS#7
-  obj.dictLookup("V", &sig_dict);
+  Object sig_dict = obj.dictLookup("V");
   if (!sig_dict.isDict()) {
-    sig_dict.free();
     return;
   }
 
-  sig_dict.dictLookup("Contents", &contents_obj);
+  Object contents_obj = sig_dict.dictLookup("Contents");
   if (contents_obj.isString()) {
     signature = contents_obj.getString()->copy();
   }
-  contents_obj.free();
 
-  sig_dict.dictLookup("ByteRange", &byte_range);
+  Object byte_range = sig_dict.dictLookup("ByteRange");
 
   // retrieve SigningTime
-  sig_dict.dictLookup("M", &time_of_signing);
+  Object time_of_signing = sig_dict.dictLookup("M");
   if (time_of_signing.isString()) {
     GooString *time_str = time_of_signing.getString();
     signature_info->setSigningTime(dateStringToTime(time_str)); // Put this information directly in SignatureInfo object
-    time_of_signing.free();
   }
 
   // check if subfilter is supported for signature validation, only detached signatures work for now
-  sig_dict.dictLookup("SubFilter", &subfilterName);
+  Object subfilterName = sig_dict.dictLookup("SubFilter");
   if (subfilterName.isName("adbe.pkcs7.detached") || subfilterName.isName("adbe.pkcs7.sha1")) {
     signature_info->setSubFilterSupport(true);
   }
-
-  subfilterName.free();
-  sig_dict.free();
 }
 
 void FormFieldSignature::hashSignedDataBlock(SignatureHandler *handler, Goffset block_len)
@@ -1508,9 +1459,8 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
 
   Goffset fileLength = doc->getBaseStream()->getLength();
   for (int i = 0; i < arrayLen/2; i++) {
-    Object offsetObj, lenObj;
-    byte_range.arrayGet(i*2, &offsetObj);
-    byte_range.arrayGet(i*2+1, &lenObj);
+    Object offsetObj = byte_range.arrayGet(i*2);
+    Object lenObj = byte_range.arrayGet(i*2+1);
 
     if (!offsetObj.isIntOrInt64() || !lenObj.isIntOrInt64()) {
       error(errSyntaxError, 0, "Illegal values in ByteRange array");
@@ -1576,50 +1526,41 @@ Form::Form(PDFDoc *docA, Object* acroFormA)
   defaultAppearance = NULL;
   defaultResources = NULL;
 
-  acroForm->dictLookup("NeedAppearances", &obj1);
+  obj1 = acroForm->dictLookup("NeedAppearances");
   needAppearances = (obj1.isBool() && obj1.getBool());
-  obj1.free();
 
-  if (acroForm->dictLookup("DA", &obj1)->isString())
+  obj1 = acroForm->dictLookup("DA");
+  if (obj1.isString())
     defaultAppearance = obj1.getString()->copy();
-  obj1.free();
 
-  if (acroForm->dictLookup("Q", &obj1)->isInt())
+  obj1 = acroForm->dictLookup("Q");
+  if (obj1.isInt())
     quadding = static_cast<VariableTextQuadding>(obj1.getInt());
-  obj1.free();
 
-  acroForm->dictLookup("DR", &resDict);
+  resDict = acroForm->dictLookup("DR");
   if (resDict.isDict()) {
     // At a minimum, this dictionary shall contain a Font entry
-    if (resDict.dictLookup("Font", &obj1)->isDict())
+    obj1 = resDict.dictLookup("Font");
+    if (obj1.isDict())
       defaultResources = new GfxResources(xref, resDict.getDict(), NULL);
-    obj1.free();
   }
   if (!defaultResources) {
-    resDict.free();
-    resDict.initNull();
+    resDict.setToNull();
   }
 
-  acroForm->dictLookup("Fields", &obj1);
+  obj1 = acroForm->dictLookup("Fields");
   if (obj1.isArray()) {
     Array *array = obj1.getArray();
-    Object obj2;
-    
     for(int i=0; i<array->getLength(); i++) {
-      Object oref;
-      array->get(i, &obj2);
-      array->getNF(i, &oref);
+      Object obj2 = array->get(i);
+      Object oref = array->getNF(i);
       if (!oref.isRef()) {
         error(errSyntaxWarning, -1, "Direct object in rootFields");
-	obj2.free();
-	oref.free();
         continue;
       }
 
       if (!obj2.isDict()) {
         error(errSyntaxWarning, -1, "Reference in Fields array to an invalid or non existent object");
-	obj2.free();
-	oref.free();
 	continue;
       }
 
@@ -1631,32 +1572,24 @@ Form::Form(PDFDoc *docA, Object* acroFormA)
       std::set<int> usedParents;
       rootFields[numFields++] = createFieldFromDict (&obj2, doc, oref.getRef(), NULL, &usedParents);
 
-      obj2.free();
-      oref.free();
     }
   } else {
     error(errSyntaxError, -1, "Can't get Fields array\n");
   }
-  obj1.free ();
 
-  acroForm->dictLookup("CO", &obj1);
+  obj1 = acroForm->dictLookup("CO");
   if (obj1.isArray()) {
     Array *array = obj1.getArray();
     calculateOrder.reserve(array->getLength());
     for(int i=0; i<array->getLength(); i++) {
-      Object oref;
-      array->getNF(i, &oref);
+      Object oref = array->getNF(i);
       if (!oref.isRef()) {
         error(errSyntaxWarning, -1, "Direct object in CO");
-        oref.free();
         continue;
       }
       calculateOrder.push_back(oref.getRef());
-
-      oref.free();
     }
   }
-  obj1.free ();
 
 #ifdef DEBUG_FORMS
   for (int i = 0; i < numFields; i++)
@@ -1671,54 +1604,43 @@ Form::~Form() {
   gfree (rootFields);
   delete defaultAppearance;
   delete defaultResources;
-  resDict.free();
 }
 
 // Look up an inheritable field dictionary entry.
-static Object *fieldLookup(Dict *field, const char *key, Object *obj, std::set<int> *usedParents) {
-  Dict *dict;
-  Object parent;
-
-  dict = field;
-  if (!dict->lookup(key, obj)->isNull()) {
+static Object fieldLookup(Dict *field, const char *key, std::set<int> *usedParents) {
+  Dict *dict = field;
+  Object obj = dict->lookup(key);
+  if (!obj.isNull()) {
     return obj;
   }
-  obj->free();
-  dict->lookupNF("Parent", &parent);
+  Object parent = dict->lookupNF("Parent");
   if (parent.isRef()) {
     const Ref ref = parent.getRef();
     if (usedParents->find(ref.num) == usedParents->end()) {
       usedParents->insert(ref.num);
 
-      Object obj2;
-      parent.fetch(dict->getXRef(), &obj2);
+      Object obj2 = parent.fetch(dict->getXRef());
       if (obj2.isDict()) {
-        fieldLookup(obj2.getDict(), key, obj, usedParents);
-      } else {
-        obj->initNull();
+        return fieldLookup(obj2.getDict(), key, usedParents);
       }
-      obj2.free();
     }
   } else if (parent.isDict()) {
-    fieldLookup(parent.getDict(), key, obj, usedParents);
-  } else {
-    obj->initNull();
+    return fieldLookup(parent.getDict(), key, usedParents);
   }
-  parent.free();
-  return obj;
+  return Object(objNull);
 }
 
-Object *Form::fieldLookup(Dict *field, const char *key, Object *obj) {
+Object Form::fieldLookup(Dict *field, const char *key) {
   std::set<int> usedParents;
-  return ::fieldLookup(field, key, obj, &usedParents);
+  return ::fieldLookup(field, key, &usedParents);
 }
 
 FormField *Form::createFieldFromDict (Object* obj, PDFDoc *docA, const Ref& pref, FormField *parent, std::set<int> *usedParents)
 {
-    Object obj2;
     FormField *field;
 
-    if (Form::fieldLookup(obj->getDict (), "FT", &obj2)->isName("Btn")) {
+    Object obj2 = Form::fieldLookup(obj->getDict (), "FT");
+    if (obj2.isName("Btn")) {
       field = new FormFieldButton(docA, obj, pref, parent, usedParents);
     } else if (obj2.isName("Tx")) {
       field = new FormFieldText(docA, obj, pref, parent, usedParents);
@@ -1729,7 +1651,6 @@ FormField *Form::createFieldFromDict (Object* obj, PDFDoc *docA, const Ref& pref
     } else { //we don't have an FT entry => non-terminal field
       field = new FormField(docA, obj, pref, parent, usedParents);
     }
-    obj2.free();
 
     return field;
 }
diff --git a/poppler/Form.h b/poppler/Form.h
index 8ddb6fe3..d73ab898 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -522,7 +522,7 @@ public:
   ~Form();
 
   // Look up an inheritable field dictionary entry.
-  static Object *fieldLookup(Dict *field, const char *key, Object *obj);
+  static Object fieldLookup(Dict *field, const char *key);
   
   /* Creates a new Field of the type specified in obj's dict.
      used in Form::Form and FormField::FormField */
diff --git a/poppler/Function.cc b/poppler/Function.cc
index 7f359b8e..04da82c8 100644
--- a/poppler/Function.cc
+++ b/poppler/Function.cc
@@ -67,7 +67,6 @@ Function *Function::parse(Object *funcObj, std::set<int> *usedParents) {
   Function *func;
   Dict *dict;
   int funcType;
-  Object obj1;
 
   if (funcObj->isStream()) {
     dict = funcObj->streamGetDict();
@@ -80,13 +79,12 @@ Function *Function::parse(Object *funcObj, std::set<int> *usedParents) {
     return NULL;
   }
 
-  if (!dict->lookup("FunctionType", &obj1)->isInt()) {
+  Object obj1 = dict->lookup("FunctionType");
+  if (!obj1.isInt()) {
     error(errSyntaxError, -1, "Function type is missing or wrong type");
-    obj1.free();
-    return NULL;
+    return nullptr;
   }
   funcType = obj1.getInt();
-  obj1.free();
 
   if (funcType == 0) {
     func = new SampledFunction(funcObj, dict);
@@ -119,75 +117,65 @@ Function::Function(const Function *func) {
 }
 
 GBool Function::init(Dict *dict) {
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
   //----- Domain
-  if (!dict->lookup("Domain", &obj1)->isArray()) {
+  obj1 = dict->lookup("Domain");
+  if (!obj1.isArray()) {
     error(errSyntaxError, -1, "Function is missing domain");
-    goto err2;
+    return gFalse;
   }
   m = obj1.arrayGetLength() / 2;
   if (m > funcMaxInputs) {
     error(errSyntaxError, -1, "Functions with more than {0:d} inputs are unsupported",
 	  funcMaxInputs);
-    goto err2;
+    return gFalse;
   }
   for (i = 0; i < m; ++i) {
-    obj1.arrayGet(2*i, &obj2);
+    Object obj2 = obj1.arrayGet(2*i);
     if (!obj2.isNum()) {
       error(errSyntaxError, -1, "Illegal value in function domain array");
-      goto err1;
+      return gFalse;
     }
     domain[i][0] = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(2*i+1, &obj2);
+    obj2 = obj1.arrayGet(2*i+1);
     if (!obj2.isNum()) {
       error(errSyntaxError, -1, "Illegal value in function domain array");
-      goto err1;
+      return gFalse;
     }
     domain[i][1] = obj2.getNum();
-    obj2.free();
   }
-  obj1.free();
 
   //----- Range
   hasRange = gFalse;
   n = 0;
-  if (dict->lookup("Range", &obj1)->isArray()) {
+  obj1 = dict->lookup("Range");
+  if (obj1.isArray()) {
     hasRange = gTrue;
     n = obj1.arrayGetLength() / 2;
     if (n > funcMaxOutputs) {
       error(errSyntaxError, -1, "Functions with more than {0:d} outputs are unsupported",
 	    funcMaxOutputs);
-      goto err2;
+      return gFalse;
     }
     for (i = 0; i < n; ++i) {
-      obj1.arrayGet(2*i, &obj2);
+      Object obj2 = obj1.arrayGet(2*i);
       if (!obj2.isNum()) {
 	error(errSyntaxError, -1, "Illegal value in function range array");
-	goto err1;
+	return gFalse;
       }
       range[i][0] = obj2.getNum();
-      obj2.free();
-      obj1.arrayGet(2*i+1, &obj2);
+      obj2 = obj1.arrayGet(2*i+1);
       if (!obj2.isNum()) {
 	error(errSyntaxError, -1, "Illegal value in function range array");
-	goto err1;
+	return gFalse;
       }
       range[i][1] = obj2.getNum();
-      obj2.free();
     }
   }
-  obj1.free();
 
   return gTrue;
-
- err1:
-  obj2.free();
- err2:
-  obj1.free();
-  return gFalse;
 }
 
 //------------------------------------------------------------------------
@@ -227,7 +215,7 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
   Stream *str;
   int sampleBits;
   double sampleMul;
-  Object obj1, obj2;
+  Object obj1;
   Guint buf, bitMask;
   int bits;
   Guint s;
@@ -241,16 +229,16 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
 
   //----- initialize the generic stuff
   if (!init(dict)) {
-    goto err1;
+    return;
   }
   if (!hasRange) {
     error(errSyntaxError, -1, "Type 0 function is missing range");
-    goto err1;
+    return;
   }
   if (m > sampledFuncMaxInputs) {
     error(errSyntaxError, -1, "Sampled functions with more than {0:d} inputs are unsupported",
 	  sampledFuncMaxInputs);
-    goto err1;
+    return;
   }
 
   //----- buffer
@@ -259,30 +247,28 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
   //----- get the stream
   if (!funcObj->isStream()) {
     error(errSyntaxError, -1, "Type 0 function isn't a stream");
-    goto err1;
+    return;
   }
   str = funcObj->getStream();
 
   //----- Size
-  if (!dict->lookup("Size", &obj1)->isArray() ||
-      obj1.arrayGetLength() != m) {
+  obj1 = dict->lookup("Size");
+  if (!obj1.isArray() || obj1.arrayGetLength() != m) {
     error(errSyntaxError, -1, "Function has missing or invalid size array");
-    goto err2;
+    return;
   }
   for (i = 0; i < m; ++i) {
-    obj1.arrayGet(i, &obj2);
+    Object obj2 = obj1.arrayGet(i);
     if (!obj2.isInt()) {
       error(errSyntaxError, -1, "Illegal value in function size array");
-      goto err3;
+      return;
     }
     sampleSize[i] = obj2.getInt();
     if (sampleSize[i] <= 0) {
       error(errSyntaxError, -1, "Illegal non-positive value in function size array");
-      goto err3;
+      return;
     }
-    obj2.free();
   }
-  obj1.free();
   idxOffset = (int *)gmallocn(1 << m, sizeof(int));
   for (i = 0; i < (1<<m); ++i) {
     idx = 0;
@@ -303,32 +289,30 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
   }
 
   //----- BitsPerSample
-  if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
+  obj1 = dict->lookup("BitsPerSample");
+  if (!obj1.isInt()) {
     error(errSyntaxError, -1, "Function has missing or invalid BitsPerSample");
-    goto err2;
+    return;
   }
   sampleBits = obj1.getInt();
   sampleMul = 1.0 / (pow(2.0, (double)sampleBits) - 1);
-  obj1.free();
 
   //----- Encode
-  if (dict->lookup("Encode", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 2*m) {
+  obj1 = dict->lookup("Encode");
+  if (obj1.isArray() && obj1.arrayGetLength() == 2*m) {
     for (i = 0; i < m; ++i) {
-      obj1.arrayGet(2*i, &obj2);
+      Object obj2 = obj1.arrayGet(2*i);
       if (!obj2.isNum()) {
 	error(errSyntaxError, -1, "Illegal value in function encode array");
-	goto err3;
+	return;
       }
       encode[i][0] = obj2.getNum();
-      obj2.free();
-      obj1.arrayGet(2*i+1, &obj2);
+      obj2 = obj1.arrayGet(2*i+1);
       if (!obj2.isNum()) {
 	error(errSyntaxError, -1, "Illegal value in function encode array");
-	goto err3;
+	return;
       }
       encode[i][1] = obj2.getNum();
-      obj2.free();
     }
   } else {
     for (i = 0; i < m; ++i) {
@@ -336,30 +320,28 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
       encode[i][1] = sampleSize[i] - 1;
     }
   }
-  obj1.free();
   for (i = 0; i < m; ++i) {
     inputMul[i] = (encode[i][1] - encode[i][0]) /
                   (domain[i][1] - domain[i][0]);
   }
 
   //----- Decode
-  if (dict->lookup("Decode", &obj1)->isArray() &&
+  obj1 = dict->lookup("Decode");
+  if (obj1.isArray() &&
       obj1.arrayGetLength() == 2*n) {
     for (i = 0; i < n; ++i) {
-      obj1.arrayGet(2*i, &obj2);
+      Object obj2 = obj1.arrayGet(2*i);
       if (!obj2.isNum()) {
 	error(errSyntaxError, -1, "Illegal value in function decode array");
-	goto err3;
+	return;
       }
       decode[i][0] = obj2.getNum();
-      obj2.free();
-      obj1.arrayGet(2*i+1, &obj2);
+      obj2 = obj1.arrayGet(2*i+1);
       if (!obj2.isNum()) {
 	error(errSyntaxError, -1, "Illegal value in function decode array");
-	goto err3;
+	return;
       }
       decode[i][1] = obj2.getNum();
-      obj2.free();
     }
   } else {
     for (i = 0; i < n; ++i) {
@@ -367,7 +349,6 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
       decode[i][1] = range[i][1];
     }
   }
-  obj1.free();
 
   //----- samples
   nSamples = n;
@@ -409,14 +390,6 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
   transform(in, cacheOut);
 
   ok = gTrue;
-  return;
-
- err3:
-  obj2.free();
- err2:
-  obj1.free();
- err1:
-  return;
 }
 
 SampledFunction::~SampledFunction() {
@@ -556,92 +529,81 @@ GBool SampledFunction::hasDifferentResultSet(Function *func) {
 //------------------------------------------------------------------------
 
 ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
-  Object obj1, obj2;
-  int i;
+  Object obj1;
 
   ok = gFalse;
 
   //----- initialize the generic stuff
   if (!init(dict)) {
-    goto err1;
+    return;
   }
   if (m != 1) {
     error(errSyntaxError, -1, "Exponential function with more than one input");
-    goto err1;
+    return;
   }
 
   //----- C0
-  if (dict->lookup("C0", &obj1)->isArray()) {
+  obj1 = dict->lookup("C0");
+  if (obj1.isArray()) {
     if (hasRange && obj1.arrayGetLength() != n) {
       error(errSyntaxError, -1, "Function's C0 array is wrong length");
-      goto err2;
+      return;
     }
     n = obj1.arrayGetLength();
     if (unlikely(n > funcMaxOutputs)) {
       error(errSyntaxError, -1, "Function's C0 array is wrong length");
       n = funcMaxOutputs;
     }
-    for (i = 0; i < n; ++i) {
-      obj1.arrayGet(i, &obj2);
+    for (int i = 0; i < n; ++i) {
+      Object obj2 = obj1.arrayGet(i);
       if (!obj2.isNum()) {
 	error(errSyntaxError, -1, "Illegal value in function C0 array");
-	goto err3;
+	return;
       }
       c0[i] = obj2.getNum();
-      obj2.free();
     }
   } else {
     if (hasRange && n != 1) {
       error(errSyntaxError, -1, "Function's C0 array is wrong length");
-      goto err2;
+      return;
     }
     n = 1;
     c0[0] = 0;
   }
-  obj1.free();
 
   //----- C1
-  if (dict->lookup("C1", &obj1)->isArray()) {
+  obj1 = dict->lookup("C1");
+  if (obj1.isArray()) {
     if (obj1.arrayGetLength() != n) {
       error(errSyntaxError, -1, "Function's C1 array is wrong length");
-      goto err2;
+      return;
     }
-    for (i = 0; i < n; ++i) {
-      obj1.arrayGet(i, &obj2);
+    for (int i = 0; i < n; ++i) {
+      Object obj2 = obj1.arrayGet(i);
       if (!obj2.isNum()) {
 	error(errSyntaxError, -1, "Illegal value in function C1 array");
-	goto err3;
+	return;
       }
       c1[i] = obj2.getNum();
-      obj2.free();
     }
   } else {
     if (n != 1) {
       error(errSyntaxError, -1, "Function's C1 array is wrong length");
-      goto err2;
+      return;
     }
     c1[0] = 1;
   }
-  obj1.free();
 
   //----- N (exponent)
-  if (!dict->lookup("N", &obj1)->isNum()) {
+  obj1 = dict->lookup("N");
+  if (!obj1.isNum()) {
     error(errSyntaxError, -1, "Function has missing or invalid N");
-    goto err2;
+    return;
   }
   e = obj1.getNum();
-  obj1.free();
 
   isLinear = fabs(e-1.) < 1e-10;
   ok = gTrue;
-  return;
-
- err3:
-  obj2.free();
- err2:
-  obj1.free();
- err1:
-  return;
 }
 
 ExponentialFunction::~ExponentialFunction() {
@@ -685,7 +647,7 @@ void ExponentialFunction::transform(double *in, double *out) {
 //------------------------------------------------------------------------
 
 StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict, std::set<int> *usedParents) {
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
   ok = gFalse;
@@ -696,17 +658,18 @@ StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict, std::set<int>
 
   //----- initialize the generic stuff
   if (!init(dict)) {
-    goto err1;
+    return;
   }
   if (m != 1) {
     error(errSyntaxError, -1, "Stitching function with more than one input");
-    goto err1;
+    return;
   }
 
   //----- Functions
-  if (!dict->lookup("Functions", &obj1)->isArray()) {
+  obj1 = dict->lookup("Functions");
+  if (!obj1.isArray()) {
     error(errSyntaxError, -1, "Missing 'Functions' entry in stitching function");
-    goto err1;
+    return;
   }
   k = obj1.arrayGetLength();
   funcs = (Function **)gmallocn(k, sizeof(Function *));
@@ -718,63 +681,58 @@ StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict, std::set<int>
   }
   for (i = 0; i < k; ++i) {
     std::set<int> usedParentsAux = *usedParents;
-    obj1.arrayGetNF(i, &obj2);
+    Object obj2 = obj1.arrayGetNF(i);
     if (obj2.isRef()) {
       const Ref ref = obj2.getRef();
       if (usedParentsAux.find(ref.num) == usedParentsAux.end()) {
         usedParentsAux.insert(ref.num);
-        obj2.free();
-        obj1.arrayGet(i, &obj2);
+        obj2 = obj1.arrayGet(i);
       } else {
-        goto err2;
+        return;
       }
     }
     if (!(funcs[i] = Function::parse(&obj2, &usedParentsAux))) {
-      goto err2;
+      return;
     }
     if (funcs[i]->getInputSize() != 1 ||
 	(i > 0 && funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) {
       error(errSyntaxError, -1,
 	    "Incompatible subfunctions in stitching function");
-      goto err2;
+      return;
     }
-    obj2.free();
   }
-  obj1.free();
 
   //----- Bounds
-  if (!dict->lookup("Bounds", &obj1)->isArray() ||
-      obj1.arrayGetLength() != k - 1) {
+  obj1 = dict->lookup("Bounds");
+  if (!obj1.isArray() || obj1.arrayGetLength() != k - 1) {
     error(errSyntaxError, -1, "Missing or invalid 'Bounds' entry in stitching function");
-    goto err1;
+    return;
   }
   bounds[0] = domain[0][0];
   for (i = 1; i < k; ++i) {
-    if (!obj1.arrayGet(i - 1, &obj2)->isNum()) {
+    Object obj2 = obj1.arrayGet(i - 1);
+    if (!obj2.isNum()) {
       error(errSyntaxError, -1, "Invalid type in 'Bounds' array in stitching function");
-      goto err2;
+      return;
     }
     bounds[i] = obj2.getNum();
-    obj2.free();
   }
   bounds[k] = domain[0][1];
-  obj1.free();
 
   //----- Encode
-  if (!dict->lookup("Encode", &obj1)->isArray() ||
-      obj1.arrayGetLength() != 2 * k) {
+  obj1 = dict->lookup("Encode");
+  if (!obj1.isArray() || obj1.arrayGetLength() != 2 * k) {
     error(errSyntaxError, -1, "Missing or invalid 'Encode' entry in stitching function");
-    goto err1;
+    return;
   }
   for (i = 0; i < 2 * k; ++i) {
-    if (!obj1.arrayGet(i, &obj2)->isNum()) {
+    Object obj2 = obj1.arrayGet(i);
+    if (!obj2.isNum()) {
       error(errSyntaxError, -1, "Invalid type in 'Encode' array in stitching function");
-      goto err2;
+      return;
     }
     encode[i] = obj2.getNum();
-    obj2.free();
   }
-  obj1.free();
 
   //----- pre-compute the scale factors
   for (i = 0; i < k; ++i) {
@@ -790,11 +748,6 @@ StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict, std::set<int>
   n = funcs[0]->getOutputSize();
   ok = gTrue;
   return;
-
- err2:
-  obj2.free();
- err1:
-  obj1.free();
 }
 
 StitchingFunction::StitchingFunction(const StitchingFunction *func) : Function(func) {
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index 2fa8c7dc..4a9aab5c 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -334,61 +334,51 @@ GfxResources::GfxResources(XRef *xref, Dict *resDictA, GfxResources *nextA) :
     // build font dictionary
     Dict *resDict = resDictA->copy(xref);
     fonts = NULL;
-    resDict->lookupNF("Font", &obj1);
+    obj1 = resDict->lookupNF("Font");
     if (obj1.isRef()) {
-      obj1.fetch(xref, &obj2);
+      obj2 = obj1.fetch(xref);
       if (obj2.isDict()) {
 	r = obj1.getRef();
 	fonts = new GfxFontDict(xref, &r, obj2.getDict());
       }
-      obj2.free();
     } else if (obj1.isDict()) {
       fonts = new GfxFontDict(xref, NULL, obj1.getDict());
     }
-    obj1.free();
 
     // get XObject dictionary
-    resDict->lookup("XObject", &xObjDict);
+    xObjDict = resDict->lookup("XObject");
 
     // get color space dictionary
-    resDict->lookup("ColorSpace", &colorSpaceDict);
+    colorSpaceDict = resDict->lookup("ColorSpace");
 
     // get pattern dictionary
-    resDict->lookup("Pattern", &patternDict);
+    patternDict = resDict->lookup("Pattern");
 
     // get shading dictionary
-    resDict->lookup("Shading", &shadingDict);
+    shadingDict = resDict->lookup("Shading");
 
     // get graphics state parameter dictionary
-    resDict->lookup("ExtGState", &gStateDict);
+    gStateDict = resDict->lookup("ExtGState");
 
     // get properties dictionary
-    resDict->lookup("Properties", &propertiesDict);
+    propertiesDict = resDict->lookup("Properties");
 
     delete resDict;
   } else {
     fonts = NULL;
-    xObjDict.initNull();
-    colorSpaceDict.initNull();
-    patternDict.initNull();
-    shadingDict.initNull();
-    gStateDict.initNull();
-    propertiesDict.initNull();
+    xObjDict.setToNull();
+    colorSpaceDict.setToNull();
+    patternDict.setToNull();
+    shadingDict.setToNull();
+    gStateDict.setToNull();
+    propertiesDict.setToNull();
   }
 
   next = nextA;
 }
 
 GfxResources::~GfxResources() {
-  if (fonts) {
-    delete fonts;
-  }
-  xObjDict.free();
-  colorSpaceDict.free();
-  patternDict.free();
-  shadingDict.free();
-  gStateDict.free();
-  propertiesDict.free();
+  delete fonts;
 }
 
 GfxFont *GfxResources::lookupFont(char *name) {
@@ -405,75 +395,73 @@ GfxFont *GfxResources::lookupFont(char *name) {
   return NULL;
 }
 
-GBool GfxResources::lookupXObject(char *name, Object *obj) {
+Object GfxResources::lookupXObject(char *name) {
   GfxResources *resPtr;
 
   for (resPtr = this; resPtr; resPtr = resPtr->next) {
     if (resPtr->xObjDict.isDict()) {
-      if (!resPtr->xObjDict.dictLookup(name, obj)->isNull())
-	return gTrue;
-      obj->free();
+      Object obj = resPtr->xObjDict.dictLookup(name);
+      if (!obj.isNull())
+	return obj;
     }
   }
   error(errSyntaxError, -1, "XObject '{0:s}' is unknown", name);
-  return gFalse;
+  return Object(objNull);
 }
 
-GBool GfxResources::lookupXObjectNF(char *name, Object *obj) {
+Object GfxResources::lookupXObjectNF(char *name) {
   GfxResources *resPtr;
 
   for (resPtr = this; resPtr; resPtr = resPtr->next) {
     if (resPtr->xObjDict.isDict()) {
-      if (!resPtr->xObjDict.dictLookupNF(name, obj)->isNull())
-	return gTrue;
-      obj->free();
+      Object obj = resPtr->xObjDict.dictLookupNF(name);
+      if (!obj.isNull())
+	return obj;
     }
   }
   error(errSyntaxError, -1, "XObject '{0:s}' is unknown", name);
-  return gFalse;
+  return Object(objNull);
 }
 
-GBool GfxResources::lookupMarkedContentNF(char *name, Object *obj) {
+Object GfxResources::lookupMarkedContentNF(char *name) {
   GfxResources *resPtr;
 
   for (resPtr = this; resPtr; resPtr = resPtr->next) {
     if (resPtr->propertiesDict.isDict()) {
-      if (!resPtr->propertiesDict.dictLookupNF(name, obj)->isNull())
-	return gTrue;
-      obj->free();
+      Object obj = resPtr->propertiesDict.dictLookupNF(name);
+      if (!obj.isNull())
+	return obj;
     }
   }
   error(errSyntaxError, -1, "Marked Content '{0:s}' is unknown", name);
-  return gFalse;
+  return Object(objNull);
 }
 
-void GfxResources::lookupColorSpace(const char *name, Object *obj) {
+Object GfxResources::lookupColorSpace(const char *name) {
   GfxResources *resPtr;
 
   for (resPtr = this; resPtr; resPtr = resPtr->next) {
     if (resPtr->colorSpaceDict.isDict()) {
-      if (!resPtr->colorSpaceDict.dictLookup(name, obj)->isNull()) {
-	return;
+      Object obj = resPtr->colorSpaceDict.dictLookup(name);
+      if (!obj.isNull()) {
+	return obj;
       }
-      obj->free();
     }
   }
-  obj->initNull();
+  return Object(objNull);
 }
 
 GfxPattern *GfxResources::lookupPattern(char *name, OutputDev *out, GfxState *state) {
   GfxResources *resPtr;
   GfxPattern *pattern;
-  Object obj;
 
   for (resPtr = this; resPtr; resPtr = resPtr->next) {
     if (resPtr->patternDict.isDict()) {
-      if (!resPtr->patternDict.dictLookup(name, &obj)->isNull()) {
+      Object obj = resPtr->patternDict.dictLookup(name);
+      if (!obj.isNull()) {
 	pattern = GfxPattern::parse(resPtr, &obj, out, state);
-	obj.free();
 	return pattern;
       }
-      obj.free();
     }
   }
   error(errSyntaxError, -1, "Unknown pattern '{0:s}'", name);
@@ -483,51 +471,50 @@ GfxPattern *GfxResources::lookupPattern(char *name, OutputDev *out, GfxState *st
 GfxShading *GfxResources::lookupShading(char *name, OutputDev *out, GfxState *state) {
   GfxResources *resPtr;
   GfxShading *shading;
-  Object obj;
 
   for (resPtr = this; resPtr; resPtr = resPtr->next) {
     if (resPtr->shadingDict.isDict()) {
-      if (!resPtr->shadingDict.dictLookup(name, &obj)->isNull()) {
+      Object obj = resPtr->shadingDict.dictLookup(name);
+      if (!obj.isNull()) {
 	shading = GfxShading::parse(resPtr, &obj, out, state);
-	obj.free();
 	return shading;
       }
-      obj.free();
     }
   }
   error(errSyntaxError, -1, "ExtGState '{0:s}' is unknown", name);
   return NULL;
 }
 
-GBool GfxResources::lookupGState(char *name, Object *obj) {
-  if (!lookupGStateNF(name, obj))
-    return gFalse;
+Object GfxResources::lookupGState(char *name) {
+  Object obj = lookupGStateNF(name);
+  if (obj.isNull())
+    return Object(objNull);
 
-  if (!obj->isRef())
-    return gTrue;
+  if (!obj.isRef())
+    return obj;
   
-  const Ref ref = obj->getRef();
-  if (!gStateCache.lookup(ref, obj)->isNull())
-    return gTrue;
-  obj->free();
+  const Ref ref = obj.getRef();
+  obj = gStateCache.lookup(ref);
+  if (!obj.isNull())
+    return obj;
 
-  gStateCache.put(ref)->copy(obj);
-  return gTrue;
+  obj = gStateCache.put(ref)->copy();
+  return obj;
 }
 
-GBool GfxResources::lookupGStateNF(char *name, Object *obj) {
+Object GfxResources::lookupGStateNF(char *name) {
   GfxResources *resPtr;
 
   for (resPtr = this; resPtr; resPtr = resPtr->next) {
     if (resPtr->gStateDict.isDict()) {
-      if (!resPtr->gStateDict.dictLookupNF(name, obj)->isNull()) {
-	return gTrue;
+      Object obj = resPtr->gStateDict.dictLookupNF(name);
+      if (!obj.isNull()) {
+	return obj;
       }
-      obj->free();
     }
   }
   error(errSyntaxError, -1, "ExtGState '{0:s}' is unknown", name);
-  return gFalse;
+  return Object(objNull);
 }
 
 //------------------------------------------------------------------------
@@ -652,17 +639,13 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict,
 #endif
 
 void Gfx::initDisplayProfile() {
-   Object catDict;
-   xref->getCatalog(&catDict);
+   Object catDict = xref->getCatalog();
    if (catDict.isDict()) {
-     Object outputIntents;
-     catDict.dictLookup("OutputIntents", &outputIntents);
+     Object outputIntents = catDict.dictLookup("OutputIntents");
      if (outputIntents.isArray() && outputIntents.arrayGetLength() == 1) {
-          Object firstElement;
-          outputIntents.arrayGet(0, &firstElement);
+          Object firstElement = outputIntents.arrayGet(0);
           if (firstElement.isDict()) {
-              Object profile;
-              firstElement.dictLookup("DestOutputProfile", &profile);
+              Object profile = firstElement.dictLookup("DestOutputProfile");
               if (profile.isStream()) {
                 Stream *iccStream = profile.getStream();
                 int length = 0;
@@ -675,13 +658,9 @@ void Gfx::initDisplayProfile() {
                 }
                 gfree(profBuf);
               }
-              profile.free();
           }
-          firstElement.free();
      }
-     outputIntents.free();
    }
-   catDict.free();
 }
 
 #endif
@@ -708,18 +687,15 @@ Gfx::~Gfx() {
 }
 
 void Gfx::display(Object *obj, GBool topLevel) {
-  Object obj2;
   int i;
 
   if (obj->isArray()) {
     for (i = 0; i < obj->arrayGetLength(); ++i) {
-      obj->arrayGet(i, &obj2);
+      Object obj2 = obj->arrayGet(i);
       if (!obj2.isStream()) {
 	error(errSyntaxError, -1, "Weird page contents");
-	obj2.free();
 	return;
       }
-      obj2.free();
     }
   } else if (!obj->isStream()) {
     error(errSyntaxError, -1, "Weird page contents");
@@ -742,7 +718,7 @@ void Gfx::go(GBool topLevel) {
   updateLevel = 1; // make sure even empty pages trigger a call to dump()
   lastAbortCheck = 0;
   numArgs = 0;
-  parser->getObj(&obj);
+  obj = parser->getObj();
   while (!obj.isEOF()) {
     commandAborted = gFalse;
 
@@ -786,9 +762,8 @@ void Gfx::go(GBool topLevel) {
 	}
 	delete timer;
       }
-      obj.free();
       for (i = 0; i < numArgs; ++i)
-	args[i].free();
+	args[i].setToNull(); // Free memory early
       numArgs = 0;
 
       // periodically update display
@@ -817,7 +792,7 @@ void Gfx::go(GBool topLevel) {
 
     // got an argument - save it
     } else if (numArgs < maxArgs) {
-      obj.shallowCopy(&args[numArgs++]);
+      args[numArgs++] = std::move(obj);
     // too many arguments - something is wrong
     } else {
       error(errSyntaxError, getPos(), "Too many args in content stream");
@@ -827,13 +802,11 @@ void Gfx::go(GBool topLevel) {
 	printf("\n");
 	fflush(stdout);
       }
-      obj.free();
     }
 
     // grab the next object
-    parser->getObj(&obj);
+    obj = parser->getObj();
   }
-  obj.free();
 
   // args at end with no command
   if (numArgs > 0) {
@@ -847,8 +820,6 @@ void Gfx::go(GBool topLevel) {
       printf("\n");
       fflush(stdout);
     }
-    for (i = 0; i < numArgs; ++i)
-      args[i].free();
   }
 
   popStateGuard();
@@ -974,7 +945,6 @@ void Gfx::opConcat(Object args[], int numArgs) {
 void Gfx::opSetDash(Object args[], int numArgs) {
   Array *a;
   int length;
-  Object obj;
   double *dash;
   int i;
 
@@ -985,11 +955,10 @@ void Gfx::opSetDash(Object args[], int numArgs) {
   } else {
     dash = (double *)gmallocn(length, sizeof(double));
     for (i = 0; i < length; ++i) {
-      a->get(i, &obj);
+      Object obj = a->get(i);
       if (obj.isNum()) {
 	dash[i] = obj.getNum();
       }
-      obj.free();
     }
   }
   state->setLineDash(dash, length, args[1].getNum());
@@ -1022,8 +991,7 @@ void Gfx::opSetLineWidth(Object args[], int numArgs) {
 }
 
 void Gfx::opSetExtGState(Object args[], int numArgs) {
-  Object obj1, obj2, obj3, obj4, obj5;
-  Object args2[2];
+  Object obj1, obj2;
   GfxBlendMode mode;
   GBool haveFillOP;
   Function *funcs[4];
@@ -1034,12 +1002,12 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
   double opac;
   int i;
 
-  if (!res->lookupGState(args[0].getName(), &obj1)) {
+  obj1 = res->lookupGState(args[0].getName());
+  if (obj1.isNull()) {
     return;
   }
   if (!obj1.isDict()) {
     error(errSyntaxError, getPos(), "ExtGState '{0:s}' is wrong type", args[0].getName());
-    obj1.free();
     return;
   }
   if (printCommands) {
@@ -1049,33 +1017,31 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
   }
 
   // parameters that are also set by individual PDF operators
-  if (obj1.dictLookup("LW", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("LW");
+  if (obj2.isNum()) {
     opSetLineWidth(&obj2, 1);
   }
-  obj2.free();
-  if (obj1.dictLookup("LC", &obj2)->isInt()) {
+  obj2 = obj1.dictLookup("LC");
+  if (obj2.isInt()) {
     opSetLineCap(&obj2, 1);
   }
-  obj2.free();
-  if (obj1.dictLookup("LJ", &obj2)->isInt()) {
+  obj2 = obj1.dictLookup("LJ");
+  if (obj2.isInt()) {
     opSetLineJoin(&obj2, 1);
   }
-  obj2.free();
-  if (obj1.dictLookup("ML", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("ML");
+  if (obj2.isNum()) {
     opSetMiterLimit(&obj2, 1);
   }
-  obj2.free();
-  if (obj1.dictLookup("D", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 2) {
-    obj2.arrayGet(0, &args2[0]);
-    obj2.arrayGet(1, &args2[1]);
+  obj2 = obj1.dictLookup("D");
+  if (obj2.isArray() && obj2.arrayGetLength() == 2) {
+    Object args2[2];
+    args2[0] = obj2.arrayGet(0);
+    args2[1] = obj2.arrayGet(1);
     if (args2[0].isArray() && args2[1].isNum()) {
       opSetDash(args2, 2);
     }
-    args2[0].free();
-    args2[1].free();
   }
-  obj2.free();
 #if 0 //~ need to add a new version of GfxResources::lookupFont() that
       //~ takes an indirect ref instead of a name
   if (obj1.dictLookup("Font", &obj2)->isArray() &&
@@ -1090,13 +1056,14 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
   }
   obj2.free();
 #endif
-  if (obj1.dictLookup("FL", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("FL");
+  if (obj2.isNum()) {
     opSetFlat(&obj2, 1);
   }
-  obj2.free();
 
   // transparency support: blend mode, fill/stroke opacity
-  if (!obj1.dictLookup("BM", &obj2)->isNull()) {
+  obj2 = obj1.dictLookup("BM");
+  if (!obj2.isNull()) {
     if (state->parseBlendMode(&obj2, &mode)) {
       state->setBlendMode(mode);
       out->updateBlendMode(state);
@@ -1104,27 +1071,27 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
       error(errSyntaxError, getPos(), "Invalid blend mode in ExtGState");
     }
   }
-  obj2.free();
-  if (obj1.dictLookup("ca", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("ca");
+  if (obj2.isNum()) {
     opac = obj2.getNum();
     state->setFillOpacity(opac < 0 ? 0 : opac > 1 ? 1 : opac);
     out->updateFillOpacity(state);
   }
-  obj2.free();
-  if (obj1.dictLookup("CA", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("CA");
+  if (obj2.isNum()) {
     opac = obj2.getNum();
     state->setStrokeOpacity(opac < 0 ? 0 : opac > 1 ? 1 : opac);
     out->updateStrokeOpacity(state);
   }
-  obj2.free();
 
   // fill/stroke overprint, overprint mode
-  if ((haveFillOP = (obj1.dictLookup("op", &obj2)->isBool()))) {
+  obj2 = obj1.dictLookup("op");
+  if ((haveFillOP = obj2.isBool())) {
     state->setFillOverprint(obj2.getBool());
     out->updateFillOverprint(state);
   }
-  obj2.free();
-  if (obj1.dictLookup("OP", &obj2)->isBool()) {
+  obj2 = obj1.dictLookup("OP");
+  if (obj2.isBool()) {
     state->setStrokeOverprint(obj2.getBool());
     out->updateStrokeOverprint(state);
     if (!haveFillOP) {
@@ -1132,24 +1099,23 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
       out->updateFillOverprint(state);
     }
   }
-  obj2.free();
-  if (obj1.dictLookup("OPM", &obj2)->isInt()) {
+  obj2 = obj1.dictLookup("OPM");
+  if (obj2.isInt()) {
     state->setOverprintMode(obj2.getInt());
     out->updateOverprintMode(state);
   }
-  obj2.free();
 
   // stroke adjust
-  if (obj1.dictLookup("SA", &obj2)->isBool()) {
+  obj2 = obj1.dictLookup("SA");
+  if (obj2.isBool()) {
     state->setStrokeAdjust(obj2.getBool());
     out->updateStrokeAdjust(state);
   }
-  obj2.free();
 
   // transfer function
-  if (obj1.dictLookup("TR2", &obj2)->isNull()) {
-    obj2.free();
-    obj1.dictLookup("TR", &obj2);
+  obj2 = obj1.dictLookup("TR2");
+  if (obj2.isNull()) {
+    obj2 = obj1.dictLookup("TR");
   }
   if (obj2.isName("Default") ||
       obj2.isName("Identity")) {
@@ -1158,9 +1124,8 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
     out->updateTransfer(state);
   } else if (obj2.isArray() && obj2.arrayGetLength() == 4) {
     for (i = 0; i < 4; ++i) {
-      obj2.arrayGet(i, &obj3);
+      Object obj3 = obj2.arrayGet(i);
       funcs[i] = Function::parse(&obj3);
-      obj3.free();
       if (!funcs[i]) {
 	break;
       }
@@ -1178,80 +1143,81 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
   } else if (!obj2.isNull()) {
     error(errSyntaxError, getPos(), "Invalid transfer function in ExtGState");
   }
-  obj2.free();
 
   // alpha is shape
-  if (obj1.dictLookup("AIS", &obj2)->isBool()) {
+  obj2 = obj1.dictLookup("AIS");
+  if (obj2.isBool()) {
     state->setAlphaIsShape(obj2.getBool());
     out->updateAlphaIsShape(state);
   }
-  obj2.free();
 
   // text knockout
-  if (obj1.dictLookup("TK", &obj2)->isBool()) {
+  obj2 = obj1.dictLookup("TK");
+  if (obj2.isBool()) {
     state->setTextKnockout(obj2.getBool());
     out->updateTextKnockout(state);
   }
-  obj2.free();
 
   // soft mask
-  if (!obj1.dictLookup("SMask", &obj2)->isNull()) {
+  obj2 = obj1.dictLookup("SMask");
+  if (!obj2.isNull()) {
     if (obj2.isName("None")) {
       out->clearSoftMask(state);
     } else if (obj2.isDict()) {
-      if (obj2.dictLookup("S", &obj3)->isName("Alpha")) {
+      Object obj3 = obj2.dictLookup("S");
+      if (obj3.isName("Alpha")) {
 	alpha = gTrue;
       } else { // "Luminosity"
 	alpha = gFalse;
       }
-      obj3.free();
       funcs[0] = NULL;
-      if (!obj2.dictLookup("TR", &obj3)->isNull()) {
+      obj3 = obj2.dictLookup("TR");
+      if (!obj3.isNull()) {
 	if (obj3.isName("Default") ||
 	    obj3.isName("Identity")) {
 	  funcs[0] = NULL;
 	} else {
 	  funcs[0] = Function::parse(&obj3);
-      if (funcs[0] == NULL ||
-          funcs[0]->getInputSize() != 1 ||
-          funcs[0]->getOutputSize() != 1) {
-	    error(errSyntaxError, getPos(),
+	  if (funcs[0] == NULL ||
+	    funcs[0]->getInputSize() != 1 ||
+	    funcs[0]->getOutputSize() != 1) {
+	      error(errSyntaxError, getPos(),
 		  "Invalid transfer function in soft mask in ExtGState");
-	    delete funcs[0];
-	    funcs[0] = NULL;
+	      delete funcs[0];
+	      funcs[0] = NULL;
 	  }
 	}
       }
-      obj3.free();
-      if ((haveBackdropColor = obj2.dictLookup("BC", &obj3)->isArray())) {
+      obj3 = obj2.dictLookup("BC");
+      if ((haveBackdropColor = obj3.isArray())) {
 	for (i = 0; i < gfxColorMaxComps; ++i) {
 	  backdropColor.c[i] = 0;
 	}
 	for (i = 0; i < obj3.arrayGetLength() && i < gfxColorMaxComps; ++i) {
-	  obj3.arrayGet(i, &obj4);
+	  Object obj4 = obj3.arrayGet(i);
 	  if (obj4.isNum()) {
 	    backdropColor.c[i] = dblToCol(obj4.getNum());
 	  }
-	  obj4.free();
 	}
       }
-      obj3.free();
-      if (obj2.dictLookup("G", &obj3)->isStream()) {
-	if (obj3.streamGetDict()->lookup("Group", &obj4)->isDict()) {
+      obj3 = obj2.dictLookup("G");
+      if (obj3.isStream()) {
+	Object obj4 = obj3.streamGetDict()->lookup("Group");
+	if (obj4.isDict()) {
 	  blendingColorSpace = NULL;
 	  isolated = knockout = gFalse;
-	  if (!obj4.dictLookup("CS", &obj5)->isNull()) {
+	  Object obj5 = obj4.dictLookup("CS");
+	  if (!obj5.isNull()) {
 	    blendingColorSpace = GfxColorSpace::parse(res, &obj5, out, state);
 	  }
-	  obj5.free();
-	  if (obj4.dictLookup("I", &obj5)->isBool()) {
+	  obj5 = obj4.dictLookup("I");
+	  if (obj5.isBool()) {
 	    isolated = obj5.getBool();
 	  }
-	  obj5.free();
-	  if (obj4.dictLookup("K", &obj5)->isBool()) {
+	  obj5 = obj4.dictLookup("K");
+	  if (obj5.isBool()) {
 	    knockout = obj5.getBool();
 	  }
-	  obj5.free();
 	  if (!haveBackdropColor) {
 	    if (blendingColorSpace) {
 	      blendingColorSpace->getDefaultColor(&backdropColor);
@@ -1270,85 +1236,70 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
 	} else {
 	  error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group");
 	}
-	obj4.free();
       } else {
 	error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group");
       }
-      obj3.free();
     } else if (!obj2.isNull()) {
       error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState");
     }
   }
-  obj2.free();
-  if (obj1.dictLookup("Font", &obj2)->isArray()) {
+  obj2 = obj1.dictLookup("Font");
+  if (obj2.isArray()) {
     GfxFont *font;
     if (obj2.arrayGetLength() == 2) {
-      Object fargs0, fargs1;
-
-      obj2.arrayGetNF(0,&fargs0);
-      obj2.arrayGet(1,&fargs1);
+      Object fargs0 = obj2.arrayGetNF(0);
+      Object fargs1 = obj2.arrayGet(1);
       if (fargs0.isRef() && fargs1.isNum()) {
-	Object fobj;
-	Ref r;
-
-	fargs0.fetch(xref, &fobj);
+	Object fobj = fargs0.fetch(xref);
 	if (fobj.isDict()) {
-	  r = fargs0.getRef();
+	  Ref r = fargs0.getRef();
 	  font = GfxFont::makeFont(xref,args[0].getName(),r,fobj.getDict());
 	  state->setFont(font,fargs1.getNum());
 	  fontChanged = gTrue;
 	}
-	fobj.free();
       }
-      fargs0.free();
-      fargs1.free();
     } else {
       error(errSyntaxError, getPos(), "Number of args mismatch for /Font in ExtGState");
     }
   }
-  obj2.free();
-  if (obj1.dictLookup("LW", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("LW");
+  if (obj2.isNum()) {
     opSetLineWidth(&obj2,1);
   }
-  obj2.free();
-  if (obj1.dictLookup("LC", &obj2)->isInt()) {
+  obj2 = obj1.dictLookup("LC");
+  if (obj2.isInt()) {
     opSetLineCap(&obj2,1);
   }
-  obj2.free();
-  if (obj1.dictLookup("LJ", &obj2)->isInt()) {
+  obj2 = obj1.dictLookup("LJ");
+  if (obj2.isInt()) {
     opSetLineJoin(&obj2,1);
   }
-  obj2.free();
-  if (obj1.dictLookup("ML", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("ML");
+  if (obj2.isNum()) {
     opSetMiterLimit(&obj2,1);
   }
-  obj2.free();
-  if (obj1.dictLookup("D", &obj2)->isArray()) {
+  obj2 = obj1.dictLookup("D");
+  if (obj2.isArray()) {
     if (obj2.arrayGetLength() == 2) {
       Object dargs[2];
 
-      obj2.arrayGetNF(0,&dargs[0]);
-      obj2.arrayGet(1,&dargs[1]);
+      dargs[0] = obj2.arrayGetNF(0);
+      dargs[1] = obj2.arrayGet(1);
       if (dargs[0].isArray() && dargs[1].isInt()) {
 	opSetDash(dargs,2);
       }
-      dargs[0].free();
-      dargs[1].free();
     } else {
       error(errSyntaxError, getPos(), "Number of args mismatch for /D in ExtGState");
     }
   }
-  obj2.free();
-  if (obj1.dictLookup("RI", &obj2)->isName()) {
+  obj2 = obj1.dictLookup("RI");
+  if (obj2.isName()) {
     opSetRenderingIntent(&obj2,1);
   }
-  obj2.free();
-  if (obj1.dictLookup("FL", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("FL");
+  if (obj2.isNum()) {
     opSetFlat(&obj2,1);
   }
-  obj2.free();
-
-  obj1.free();
 }
 
 void Gfx::doSoftMask(Object *str, GBool alpha,
@@ -1357,7 +1308,7 @@ void Gfx::doSoftMask(Object *str, GBool alpha,
 		     Function *transferFunc, GfxColor *backdropColor) {
   Dict *dict, *resDict;
   double m[6], bbox[4];
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
   // check for excessive recursion
@@ -1369,50 +1320,42 @@ void Gfx::doSoftMask(Object *str, GBool alpha,
   dict = str->streamGetDict();
 
   // check form type
-  dict->lookup("FormType", &obj1);
+  obj1 = dict->lookup("FormType");
   if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
     error(errSyntaxError, getPos(), "Unknown form type");
   }
-  obj1.free();
 
   // get bounding box
-  dict->lookup("BBox", &obj1);
+  obj1 = dict->lookup("BBox");
   if (!obj1.isArray()) {
-    obj1.free();
     error(errSyntaxError, getPos(), "Bad form bounding box");
     return;
   }
   for (i = 0; i < 4; ++i) {
-    obj1.arrayGet(i, &obj2);
+    Object obj2 = obj1.arrayGet(i);
     if (likely(obj2.isNum())) bbox[i] = obj2.getNum();
     else {
-      obj2.free();
-      obj1.free();
       error(errSyntaxError, getPos(), "Bad form bounding box (non number)");
       return;
     }
-    obj2.free();
   }
-  obj1.free();
 
   // get matrix
-  dict->lookup("Matrix", &obj1);
+  obj1 = dict->lookup("Matrix");
   if (obj1.isArray()) {
     for (i = 0; i < 6; ++i) {
-      obj1.arrayGet(i, &obj2);
+      Object obj2 = obj1.arrayGet(i);
       if (likely(obj2.isNum())) m[i] = obj2.getNum();
       else m[i] = 0;
-      obj2.free();
     }
   } else {
     m[0] = 1; m[1] = 0;
     m[2] = 0; m[3] = 1;
     m[4] = 0; m[5] = 0;
   }
-  obj1.free();
 
   // get resources
-  dict->lookup("Resources", &obj1);
+  obj1 = dict->lookup("Resources");
   resDict = obj1.isDict() ? obj1.getDict() : (Dict *)NULL;
 
   // draw it
@@ -1425,7 +1368,6 @@ void Gfx::doSoftMask(Object *str, GBool alpha,
   if (blendingColorSpace) {
     delete blendingColorSpace;
   }
-  obj1.free();
 }
 
 void Gfx::opSetRenderingIntent(Object args[], int numArgs) {
@@ -1439,17 +1381,15 @@ void Gfx::opSetRenderingIntent(Object args[], int numArgs) {
 void Gfx::opSetFillGray(Object args[], int numArgs) {
   GfxColor color;
   GfxColorSpace *colorSpace = NULL;
-  Object obj;
 
   state->setFillPattern(NULL);
-  res->lookupColorSpace("DefaultGray", &obj);
+  Object obj = res->lookupColorSpace("DefaultGray");
   if (!obj.isNull()) {
     colorSpace = GfxColorSpace::parse(res, &obj, out, state);
   }
   if (colorSpace == NULL) {
     colorSpace = new GfxDeviceGrayColorSpace();
   }
-  obj.free();
   state->setFillColorSpace(colorSpace);
   out->updateFillColorSpace(state);
   color.c[0] = dblToCol(args[0].getNum());
@@ -1460,17 +1400,15 @@ void Gfx::opSetFillGray(Object args[], int numArgs) {
 void Gfx::opSetStrokeGray(Object args[], int numArgs) {
   GfxColor color;
   GfxColorSpace *colorSpace = NULL;
-  Object obj;
 
   state->setStrokePattern(NULL);
-  res->lookupColorSpace("DefaultGray", &obj);
+  Object obj = res->lookupColorSpace("DefaultGray");
   if (!obj.isNull()) {
     colorSpace = GfxColorSpace::parse(res, &obj, out, state);
   }
   if (colorSpace == NULL) {
     colorSpace = new GfxDeviceGrayColorSpace();
   }
-  obj.free();
   state->setStrokeColorSpace(colorSpace);
   out->updateStrokeColorSpace(state);
   color.c[0] = dblToCol(args[0].getNum());
@@ -1481,17 +1419,15 @@ void Gfx::opSetStrokeGray(Object args[], int numArgs) {
 void Gfx::opSetFillCMYKColor(Object args[], int numArgs) {
   GfxColor color;
   GfxColorSpace *colorSpace = NULL;
-  Object obj;
   int i;
 
-  res->lookupColorSpace("DefaultCMYK", &obj);
+  Object obj = res->lookupColorSpace("DefaultCMYK");
   if (!obj.isNull()) {
     colorSpace = GfxColorSpace::parse(res, &obj, out, state);
   }
   if (colorSpace == NULL) {
     colorSpace = new GfxDeviceCMYKColorSpace();
   }
-  obj.free();
   state->setFillPattern(NULL);
   state->setFillColorSpace(colorSpace);
   out->updateFillColorSpace(state);
@@ -1505,18 +1441,16 @@ void Gfx::opSetFillCMYKColor(Object args[], int numArgs) {
 void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) {
   GfxColor color;
   GfxColorSpace *colorSpace = NULL;
-  Object obj;
   int i;
 
   state->setStrokePattern(NULL);
-  res->lookupColorSpace("DefaultCMYK", &obj);
+  Object obj = res->lookupColorSpace("DefaultCMYK");
   if (!obj.isNull()) {
     colorSpace = GfxColorSpace::parse(res, &obj, out, state);
   }
   if (colorSpace == NULL) {
     colorSpace = new GfxDeviceCMYKColorSpace();
   }
-  obj.free();
   state->setStrokeColorSpace(colorSpace);
   out->updateStrokeColorSpace(state);
   for (i = 0; i < 4; ++i) {
@@ -1527,20 +1461,18 @@ void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) {
 }
 
 void Gfx::opSetFillRGBColor(Object args[], int numArgs) {
-  Object obj;
   GfxColorSpace *colorSpace = NULL;
   GfxColor color;
   int i;
 
   state->setFillPattern(NULL);
-  res->lookupColorSpace("DefaultRGB", &obj);
+  Object obj = res->lookupColorSpace("DefaultRGB");
   if (!obj.isNull()) {
     colorSpace = GfxColorSpace::parse(res, &obj, out, state);
   }
   if (colorSpace == NULL) {
     colorSpace = new GfxDeviceRGBColorSpace();
   }
-  obj.free();
   state->setFillColorSpace(colorSpace);
   out->updateFillColorSpace(state);
   for (i = 0; i < 3; ++i) {
@@ -1551,20 +1483,18 @@ void Gfx::opSetFillRGBColor(Object args[], int numArgs) {
 }
 
 void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) {
-  Object obj;
   GfxColorSpace *colorSpace = NULL;
   GfxColor color;
   int i;
 
   state->setStrokePattern(NULL);
-  res->lookupColorSpace("DefaultRGB", &obj);
+  Object obj = res->lookupColorSpace("DefaultRGB");
   if (!obj.isNull()) {
     colorSpace = GfxColorSpace::parse(res, &obj, out, state);
   }
   if (colorSpace == NULL) {
     colorSpace = new GfxDeviceRGBColorSpace();
   }
-  obj.free();
   state->setStrokeColorSpace(colorSpace);
   out->updateStrokeColorSpace(state);
   for (i = 0; i < 3; ++i) {
@@ -1575,17 +1505,15 @@ void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) {
 }
 
 void Gfx::opSetFillColorSpace(Object args[], int numArgs) {
-  Object obj;
   GfxColorSpace *colorSpace;
   GfxColor color;
 
-  res->lookupColorSpace(args[0].getName(), &obj);
+  Object obj = res->lookupColorSpace(args[0].getName());
   if (obj.isNull()) {
     colorSpace = GfxColorSpace::parse(res, &args[0], out, state);
   } else {
     colorSpace = GfxColorSpace::parse(res, &obj, out, state);
   }
-  obj.free();
   if (colorSpace) {
     state->setFillPattern(NULL);
     state->setFillColorSpace(colorSpace);
@@ -1599,18 +1527,16 @@ void Gfx::opSetFillColorSpace(Object args[], int numArgs) {
 }
 
 void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) {
-  Object obj;
   GfxColorSpace *colorSpace;
   GfxColor color;
 
   state->setStrokePattern(NULL);
-  res->lookupColorSpace(args[0].getName(), &obj);
+  Object obj = res->lookupColorSpace(args[0].getName());
   if (obj.isNull()) {
     colorSpace = GfxColorSpace::parse(res, &args[0], out, state);
   } else {
     colorSpace = GfxColorSpace::parse(res, &obj, out, state);
   }
-  obj.free();
   if (colorSpace) {
     state->setStrokeColorSpace(colorSpace);
     out->updateStrokeColorSpace(state);
@@ -3885,7 +3811,6 @@ void Gfx::opMoveSetShowText(Object args[], int numArgs) {
 
 void Gfx::opShowSpaceText(Object args[], int numArgs) {
   Array *a;
-  Object obj;
   int wMode;
   int i;
 
@@ -3901,7 +3826,7 @@ void Gfx::opShowSpaceText(Object args[], int numArgs) {
   wMode = state->getFont()->getWMode();
   a = args[0].getArray();
   for (i = 0; i < a->getLength(); ++i) {
-    a->get(i, &obj);
+    Object obj = a->get(i);
     if (obj.isNum()) {
       // this uses the absolute value of the font size to match
       // Acrobat's behavior
@@ -3920,17 +3845,15 @@ void Gfx::opShowSpaceText(Object args[], int numArgs) {
       error(errSyntaxError, getPos(),
         "Element of show/space array must be number or string");
     }
-    obj.free();
   }
   out->endStringOp(state);
   if (!ocState) {
     a = args[0].getArray();
     for (i = 0; i < a->getLength(); ++i) {
-      a->get(i, &obj);
+      Object obj = a->get(i);
       if (obj.isString()) {
 	doIncCharCount(obj.getString());
       }
-      obj.free();
     }
   }
 }
@@ -3946,7 +3869,6 @@ void Gfx::doShowText(GooString *s) {
   double x0, y0, x1, y1;
   double oldCTM[6], newCTM[6];
   double *mat;
-  Object charProc;
   Dict *resDict;
   Parser *oldParser;
   GfxState *savedState;
@@ -4030,7 +3952,7 @@ void Gfx::doShowText(GooString *s) {
       state->transformDelta(dx, dy, &ddx, &ddy);
       if (!out->beginType3Char(state, curX + riseX, curY + riseY, ddx, ddy,
 			       code, u, uLen)) {
-	((Gfx8BitFont *)font)->getCharProc(code, &charProc);
+	Object charProc = ((Gfx8BitFont *)font)->getCharProc(code);
 	if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
 	  pushResources(resDict);
 	}
@@ -4043,7 +3965,6 @@ void Gfx::doShowText(GooString *s) {
 	if (resDict) {
 	  popResources();
 	}
-	charProc.free();
       }
       restoreStateStack(savedState);
       // GfxState::restore() does *not* restore the current position,
@@ -4181,39 +4102,34 @@ void Gfx::doIncCharCount(GooString *s) {
 
 void Gfx::opXObject(Object args[], int numArgs) {
   char *name;
-  Object obj1, obj2, obj3, refObj;
-#if OPI_SUPPORT
-  Object opiDict;
-#endif
 
   if (!ocState && !out->needCharCount()) {
     return;
   }
   name = args[0].getName();
-  if (!res->lookupXObject(name, &obj1)) {
+  Object obj1 = res->lookupXObject(name);
+  if (obj1.isNull()) {
     return;
   }
   if (!obj1.isStream()) {
       error(errSyntaxError, getPos(), "XObject '{0:s}' is wrong type", name);
-    obj1.free();
     return;
   }
 
 #if OPI_SUPPORT
-  obj1.streamGetDict()->lookup("OPI", &opiDict);
+  Object opiDict = obj1.streamGetDict()->lookup("OPI");
   if (opiDict.isDict()) {
     out->opiBegin(state, opiDict.getDict());
   }
 #endif
-  obj1.streamGetDict()->lookup("Subtype", &obj2);
+  Object obj2 = obj1.streamGetDict()->lookup("Subtype");
   if (obj2.isName("Image")) {
     if (out->needNonText()) {
-      res->lookupXObjectNF(name, &refObj);
+      Object refObj = res->lookupXObjectNF(name);
       doImage(&refObj, obj1.getStream(), gFalse);
-      refObj.free();
     }
   } else if (obj2.isName("Form")) {
-    res->lookupXObjectNF(name, &refObj);
+    Object refObj = res->lookupXObjectNF(name);
     GBool shouldDoForm = gTrue;
     std::set<int>::iterator drawingFormIt;
     if (refObj.isRef()) {
@@ -4234,9 +4150,8 @@ void Gfx::opXObject(Object args[], int numArgs) {
     if (refObj.isRef() && shouldDoForm) {
       formsDrawing.erase(drawingFormIt);
     }
-    refObj.free();
   } else if (obj2.isName("PS")) {
-    obj1.streamGetDict()->lookup("Level1", &obj3);
+    Object obj3 = obj1.streamGetDict()->lookup("Level1");
     out->psXObject(obj1.getStream(),
 		   obj3.isStream() ? obj3.getStream() : (Stream *)NULL);
   } else if (obj2.isName()) {
@@ -4244,14 +4159,11 @@ void Gfx::opXObject(Object args[], int numArgs) {
   } else {
     error(errSyntaxError, getPos(), "XObject subtype is missing or wrong type");
   }
-  obj2.free();
 #if OPI_SUPPORT
   if (opiDict.isDict()) {
     out->opiEnd(state, opiDict.getDict());
   }
-  opiDict.free();
 #endif
-  obj1.free();
 }
 
 void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
@@ -4264,7 +4176,6 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
   GBool invert;
   GfxColorSpace *colorSpace, *maskColorSpace;
   GfxImageColorMap *maskColorMap;
-  Object maskObj, smaskObj;
   GBool haveColorKeyMask, haveExplicitMask, haveSoftMask;
   int maskColors[2*gfxColorMaxComps];
   int maskWidth, maskHeight;
@@ -4284,84 +4195,72 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
 
   // check for optional content key
   if (ref) {
-    dict->lookupNF("OC", &obj1);
+    obj1 = dict->lookupNF("OC");
     if (catalog->getOptContentConfig() && !catalog->getOptContentConfig()->optContentIsVisible(&obj1)) {
-      obj1.free();
       return;
     }
-    obj1.free();
   }
 
   // get size
-  dict->lookup("Width", &obj1);
+  obj1 = dict->lookup("Width");
   if (obj1.isNull()) {
-    obj1.free();
-    dict->lookup("W", &obj1);
+    obj1 = dict->lookup("W");
   }
   if (obj1.isInt())
     width = obj1.getInt();
   else if (obj1.isReal())
     width = (int)obj1.getReal();
   else
-    goto err2;
-  obj1.free();
-  dict->lookup("Height", &obj1);
+    goto err1;
+  obj1 = dict->lookup("Height");
   if (obj1.isNull()) {
-    obj1.free();
-    dict->lookup("H", &obj1);
+    obj1 = dict->lookup("H");
   }
   if (obj1.isInt())
     height = obj1.getInt();
   else if (obj1.isReal())
     height = (int)obj1.getReal();
   else
-    goto err2;
-  obj1.free();
+    goto err1;
 
   if (width < 1 || height < 1)
     goto err1;
 
   // image interpolation
-  dict->lookup("Interpolate", &obj1);
+  obj1 = dict->lookup("Interpolate");
   if (obj1.isNull()) {
-    obj1.free();
-    dict->lookup("I", &obj1);
+    obj1 = dict->lookup("I");
   }
   if (obj1.isBool())
     interpolate = obj1.getBool();
   else
     interpolate = gFalse;
-  obj1.free();
   maskInterpolate = gFalse;
 
   // image or mask?
-  dict->lookup("ImageMask", &obj1);
+  obj1 = dict->lookup("ImageMask");
   if (obj1.isNull()) {
-    obj1.free();
-    dict->lookup("IM", &obj1);
+    obj1 = dict->lookup("IM");
   }
   mask = gFalse;
   if (obj1.isBool())
     mask = obj1.getBool();
   else if (!obj1.isNull())
-    goto err2;
-  obj1.free();
+    goto err1;
 
   // bit depth
   if (bits == 0) {
-    dict->lookup("BitsPerComponent", &obj1);
+    obj1 = dict->lookup("BitsPerComponent");
     if (obj1.isNull()) {
-      obj1.free();
-      dict->lookup("BPC", &obj1);
+      obj1 = dict->lookup("BPC");
     }
     if (obj1.isInt()) {
       bits = obj1.getInt();
     } else if (mask) {
       bits = 1;
     } else {
-      goto err2;
+      goto err1;
     }
-    obj1.free();
   }
 
   // display a mask
@@ -4371,22 +4270,20 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
     if (bits != 1)
       goto err1;
     invert = gFalse;
-    dict->lookup("Decode", &obj1);
+    obj1 = dict->lookup("Decode");
     if (obj1.isNull()) {
-      obj1.free();
-      dict->lookup("D", &obj1);
+      obj1 = dict->lookup("D");
     }
     if (obj1.isArray()) {
       Object obj2;
-      obj1.arrayGet(0, &obj2);
+      obj2 = obj1.arrayGet(0);
       // Table 4.39 says /Decode must be [1 0] or [0 1]. Adobe
       // accepts [1.0 0.0] as well.
       if (obj2.isNum() && obj2.getNum() >= 0.9)
 	invert = gTrue;
     } else if (!obj1.isNull()) {
-      goto err2;
+      goto err1;
     }
-    obj1.free();
 
     // if drawing is disabled, skip over inline image data
     if (!ocState || !out->needNonText()) {
@@ -4411,22 +4308,19 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
     }
 
     // get color space and color map
-    dict->lookup("ColorSpace", &obj1);
+    obj1 = dict->lookup("ColorSpace");
     if (obj1.isNull()) {
-      obj1.free();
-      dict->lookup("CS", &obj1);
+      obj1 = dict->lookup("CS");
     }
     if (obj1.isName() && inlineImg) {
-      Object obj2;
-      res->lookupColorSpace(obj1.getName(), &obj2);
+      Object obj2 = res->lookupColorSpace(obj1.getName());
       if (!obj2.isNull()) {
-	obj2.shallowCopy(&obj1);
+	obj1 = std::move(obj2);
       }
     }
     if (!obj1.isNull()) {
-      Object objIntent;
       char *tempIntent = NULL;
-      dict->lookup("Intent", &objIntent);
+      Object objIntent = dict->lookup("Intent");
       if (objIntent.isName()) {
         tempIntent = state->getRenderingIntent();
         if (tempIntent != NULL) {
@@ -4439,48 +4333,38 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
         state->setRenderingIntent(tempIntent);
         free(tempIntent);
       }
-      objIntent.free();
     } else if (csMode == streamCSDeviceGray) {
-      Object objCS;
-      res->lookupColorSpace("DefaultGray", &objCS);
+      Object objCS = res->lookupColorSpace("DefaultGray");
       if (objCS.isNull()) {
         colorSpace = new GfxDeviceGrayColorSpace();
       } else {
         colorSpace = GfxColorSpace::parse(res, &objCS, out, state);
       }
-      objCS.free();
     } else if (csMode == streamCSDeviceRGB) {
-      Object objCS;
-      res->lookupColorSpace("DefaultRGB", &objCS);
+      Object objCS = res->lookupColorSpace("DefaultRGB");
       if (objCS.isNull()) {
         colorSpace = new GfxDeviceRGBColorSpace();
       } else {
         colorSpace = GfxColorSpace::parse(res, &objCS, out, state);
       }
-      objCS.free();
     } else if (csMode == streamCSDeviceCMYK) {
-      Object objCS;
-      res->lookupColorSpace("DefaultCMYK", &objCS);
+      Object objCS = res->lookupColorSpace("DefaultCMYK");
       if (objCS.isNull()) {
         colorSpace = new GfxDeviceCMYKColorSpace();
       } else {
         colorSpace = GfxColorSpace::parse(res, &objCS, out, state);
       }
-      objCS.free();
     } else {
       colorSpace = NULL;
     }
-    obj1.free();
     if (!colorSpace) {
       goto err1;
     }
-    dict->lookup("Decode", &obj1);
+    obj1 = dict->lookup("Decode");
     if (obj1.isNull()) {
-      obj1.free();
-      dict->lookup("D", &obj1);
+      obj1 = dict->lookup("D");
     }
     GfxImageColorMap colorMap(bits, &obj1, colorSpace);
-    obj1.free();
     if (!colorMap.isOk()) {
       goto err1;
     }
@@ -4491,8 +4375,8 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
     maskWidth = maskHeight = 0; // make gcc happy
     maskInvert = gFalse; // make gcc happy
     maskColorMap = NULL; // make gcc happy
-    dict->lookup("Mask", &maskObj);
-    dict->lookup("SMask", &smaskObj);
+    Object maskObj = dict->lookup("Mask");
+    Object smaskObj = dict->lookup("SMask");
     if (smaskObj.isStream()) {
       // soft mask
       if (inlineImg) {
@@ -4500,76 +4384,63 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
       }
       maskStr = smaskObj.getStream();
       maskDict = smaskObj.streamGetDict();
-      maskDict->lookup("Width", &obj1);
+      obj1 = maskDict->lookup("Width");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("W", &obj1);
+	obj1 = maskDict->lookup("W");
       }
       if (!obj1.isInt()) {
-	goto err2;
+	goto err1;
       }
       maskWidth = obj1.getInt();
-      obj1.free();
-      maskDict->lookup("Height", &obj1);
+      obj1 = maskDict->lookup("Height");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("H", &obj1);
+	obj1 = maskDict->lookup("H");
       }
       if (!obj1.isInt()) {
-	goto err2;
+	goto err1;
       }
       maskHeight = obj1.getInt();
-      obj1.free();
-      maskDict->lookup("Interpolate", &obj1);
+      obj1 = maskDict->lookup("Interpolate");
       if (obj1.isNull()) {
-        obj1.free();
-        maskDict->lookup("I", &obj1);
+        obj1 = maskDict->lookup("I");
       }
       if (obj1.isBool())
         maskInterpolate = obj1.getBool();
       else
         maskInterpolate = gFalse;
-      obj1.free();
-      maskDict->lookup("BitsPerComponent", &obj1);
+      obj1 = maskDict->lookup("BitsPerComponent");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("BPC", &obj1);
+	obj1 = maskDict->lookup("BPC");
       }
       if (!obj1.isInt()) {
-	goto err2;
+	goto err1;
       }
       maskBits = obj1.getInt();
-      obj1.free();
-      maskDict->lookup("ColorSpace", &obj1);
+      obj1 = maskDict->lookup("ColorSpace");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("CS", &obj1);
+	obj1 = maskDict->lookup("CS");
       }
       if (obj1.isName()) {
-	Object obj2;
-	res->lookupColorSpace(obj1.getName(), &obj2);
+	Object obj2 = res->lookupColorSpace(obj1.getName());
 	if (!obj2.isNull()) {
-	  obj2.shallowCopy(&obj1);
+	  obj1 = std::move(obj2);
 	}
       }
       maskColorSpace = GfxColorSpace::parse(NULL, &obj1, out, state);
-      obj1.free();
       if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) {
 	goto err1;
       }
-      maskDict->lookup("Decode", &obj1);
+      obj1 = maskDict->lookup("Decode");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("D", &obj1);
+	obj1 = maskDict->lookup("D");
       }
       maskColorMap = new GfxImageColorMap(maskBits, &obj1, maskColorSpace);
-      obj1.free();
       if (!maskColorMap->isOk()) {
 	delete maskColorMap;
 	goto err1;
       }
       // handle the Matte entry
-      maskDict->lookup("Matte", &obj1);
+      obj1 = maskDict->lookup("Matte");
       if (obj1.isArray()) {
         if (obj1.getArray()->getLength() != colorSpace->getNComps()) {
           error(errSyntaxError, -1, "Matte entry should have {0:d} components but has {1:d}",
@@ -4579,11 +4450,9 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
             maskWidth, maskHeight, width, height);
         } else {
           GfxColor matteColor;
-          Object obj2;
           for (i = 0; i < colorSpace->getNComps(); i++) {
-            obj1.getArray()->get(i, &obj2);
+            Object obj2 = obj1.getArray()->get(i);
             if (!obj2.isNum()) {
-              obj2.free();
               error(errSyntaxError, -1, "Matte entry {0:d} should be a number but it's of type {1:d}", i, obj2.getType());
 
               break;
@@ -4595,14 +4464,13 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
           }
         }
       }
-      obj1.free();
       haveSoftMask = gTrue;
     } else if (maskObj.isArray()) {
       // color key mask
       for (i = 0;
 	   i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps;
 	   ++i) {
-	maskObj.arrayGet(i, &obj1);
+	obj1 = maskObj.arrayGet(i);
 	if (obj1.isInt()) {
 	  maskColors[i] = obj1.getInt();
 	} else if (obj1.isReal()) {
@@ -4610,10 +4478,8 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
 	  maskColors[i] = (int) obj1.getReal();
 	} else {
 	  error(errSyntaxError, -1, "Mask entry should be an integer but it's of type {0:d}", obj1.getType());
-	  obj1.free();
 	  goto err1;
 	}
-	obj1.free();
       }
       haveColorKeyMask = gTrue;
     } else if (maskObj.isStream()) {
@@ -4623,63 +4489,52 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
       }
       maskStr = maskObj.getStream();
       maskDict = maskObj.streamGetDict();
-      maskDict->lookup("Width", &obj1);
+      obj1 = maskDict->lookup("Width");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("W", &obj1);
+	obj1 = maskDict->lookup("W");
       }
       if (!obj1.isInt()) {
-	goto err2;
+	goto err1;
       }
       maskWidth = obj1.getInt();
-      obj1.free();
-      maskDict->lookup("Height", &obj1);
+      obj1 = maskDict->lookup("Height");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("H", &obj1);
+	obj1 = maskDict->lookup("H");
       }
       if (!obj1.isInt()) {
-	goto err2;
+	goto err1;
       }
       maskHeight = obj1.getInt();
-      obj1.free();
-      maskDict->lookup("Interpolate", &obj1);
+      obj1 = maskDict->lookup("Interpolate");
       if (obj1.isNull()) {
-        obj1.free();
-	maskDict->lookup("I", &obj1);
+	obj1 = maskDict->lookup("I");
       }
       if (obj1.isBool())
         maskInterpolate = obj1.getBool();
       else
         maskInterpolate = gFalse;
-      obj1.free();
-      maskDict->lookup("ImageMask", &obj1);
+      obj1 = maskDict->lookup("ImageMask");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("IM", &obj1);
+	obj1 = maskDict->lookup("IM");
       }
       if (!obj1.isBool() || !obj1.getBool()) {
-	goto err2;
+	goto err1;
       }
-      obj1.free();
       maskInvert = gFalse;
-      maskDict->lookup("Decode", &obj1);
+      obj1 = maskDict->lookup("Decode");
       if (obj1.isNull()) {
-	obj1.free();
-	maskDict->lookup("D", &obj1);
+	obj1 = maskDict->lookup("D");
       }
       if (obj1.isArray()) {
-	Object obj2;
-	obj1.arrayGet(0, &obj2);
+	Object obj2 = obj1.arrayGet(0);
 	// Table 4.39 says /Decode must be [1 0] or [0 1]. Adobe
 	// accepts [1.0 0.0] as well.
 	if (obj2.isNum() && obj2.getNum() >= 0.9) {
 	  maskInvert = gTrue;
 	}
       } else if (!obj1.isNull()) {
-	goto err2;
+	goto err1;
       }
-      obj1.free();
       haveExplicitMask = gTrue;
     }
 
@@ -4707,9 +4562,6 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
 		       haveColorKeyMask ? maskColors : (int *)NULL, inlineImg);
       }
     }
-
-    maskObj.free();
-    smaskObj.free();
   }
 
   if ((i = width * height) > 1000) {
@@ -4719,8 +4571,6 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
 
   return;
 
- err2:
-  obj1.free();
  err1:
   error(errSyntaxError, getPos(), "Bad image parameters");
 }
@@ -4728,22 +4578,22 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
 GBool Gfx::checkTransparencyGroup(Dict *resDict) {
   // check the effect of compositing objects as a group:
   // look for ExtGState entries with ca != 1 or CA != 1 or BM != normal
-  Object extGStates;
   GBool transpGroup = gFalse;
   double opac;
 
   if (resDict == NULL)
     return gFalse;
   pushResources(resDict);
-  resDict->lookup("ExtGState", &extGStates);
+  Object extGStates = resDict->lookup("ExtGState");
   if (extGStates.isDict()) {
     Dict *dict = extGStates.getDict();
     for (int i = 0; i < dict->getLength() && !transpGroup; i++) {
-      Object obj1, obj2;
       GfxBlendMode mode;
 
-      if (res->lookupGState(dict->getKey(i), &obj1) && obj1.isDict()) {
-        if (!obj1.dictLookup("BM", &obj2)->isNull()) {
+      Object obj1 = res->lookupGState(dict->getKey(i));
+      if (obj1.isDict()) {
+        Object obj2 = obj1.dictLookup("BM");
+        if (!obj2.isNull()) {
           if (state->parseBlendMode(&obj2, &mode)) {
             if (mode != gfxBlendNormal)
               transpGroup = gTrue;
@@ -4751,38 +4601,35 @@ GBool Gfx::checkTransparencyGroup(Dict *resDict) {
             error(errSyntaxError, getPos(), "Invalid blend mode in ExtGState");
           }
         }
-        obj2.free();
-        if (obj1.dictLookup("ca", &obj2)->isNum()) {
+        obj2 = obj1.dictLookup("ca");
+	if (obj2.isNum()) {
           opac = obj2.getNum();
           opac = opac < 0 ? 0 : opac > 1 ? 1 : opac;
           if (opac != 1)
             transpGroup = gTrue;
         }
-        obj2.free();
-        if (obj1.dictLookup("CA", &obj2)->isNum()) {
+        obj2 = obj1.dictLookup("CA");
+	if (obj2.isNum()) {
           opac = obj2.getNum();
           opac = opac < 0 ? 0 : opac > 1 ? 1 : opac;
           if (opac != 1)
             transpGroup = gTrue;
         }
-        obj2.free();
         // alpha is shape
-        if (!transpGroup && obj1.dictLookup("AIS", &obj2)->isBool()) {
+	obj2 = obj1.dictLookup("AIS");
+        if (!transpGroup && obj2.isBool()) {
           transpGroup = obj2.getBool();
         }
-        obj2.free();
         // soft mask
-        if (!transpGroup && !obj1.dictLookup("SMask", &obj2)->isNull()) {
+	obj2 = obj1.dictLookup("SMask");
+        if (!transpGroup && !obj2.isNull()) {
           if (!obj2.isName("None")) {
             transpGroup = gTrue;
           }
         }
-        obj2.free();
       }
-      obj1.free();
     }
   }
-  extGStates.free();
   popResources();
   return transpGroup;
 }
@@ -4791,12 +4638,10 @@ void Gfx::doForm(Object *str) {
   Dict *dict;
   GBool transpGroup, isolated, knockout;
   GfxColorSpace *blendingColorSpace;
-  Object matrixObj, bboxObj;
   double m[6], bbox[4];
-  Object resObj;
   Dict *resDict;
   GBool ocSaved;
-  Object obj1, obj2, obj3;
+  Object obj1;
   int i;
 
   // check for excessive recursion
@@ -4808,88 +4653,79 @@ void Gfx::doForm(Object *str) {
   dict = str->streamGetDict();
 
   // check form type
-  dict->lookup("FormType", &obj1);
+  obj1 = dict->lookup("FormType");
   if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
     error(errSyntaxError, getPos(), "Unknown form type");
   }
-  obj1.free();
 
   // check for optional content key
   ocSaved = ocState;
-  dict->lookupNF("OC", &obj1);
+  obj1 = dict->lookupNF("OC");
   if (catalog->getOptContentConfig() && !catalog->getOptContentConfig()->optContentIsVisible(&obj1)) {
-    obj1.free();
     if (out->needCharCount()) {
       ocState = gFalse;
     } else {
       return;
     }
   }
-  obj1.free();
 
   // get bounding box
-  dict->lookup("BBox", &bboxObj);
+  Object bboxObj = dict->lookup("BBox");
   if (!bboxObj.isArray()) {
-    bboxObj.free();
     error(errSyntaxError, getPos(), "Bad form bounding box");
     ocState = ocSaved;
     return;
   }
   for (i = 0; i < 4; ++i) {
-    bboxObj.arrayGet(i, &obj1);
+    obj1 = bboxObj.arrayGet(i);
     if (likely(obj1.isNum())) {
       bbox[i] = obj1.getNum();
-      obj1.free();
     } else {
-      obj1.free();
       error(errSyntaxError, getPos(), "Bad form bounding box value");
       return;
     }
   }
-  bboxObj.free();
 
   // get matrix
-  dict->lookup("Matrix", &matrixObj);
+  Object matrixObj = dict->lookup("Matrix");
   if (matrixObj.isArray()) {
     for (i = 0; i < 6; ++i) {
-      matrixObj.arrayGet(i, &obj1);
+      obj1 = matrixObj.arrayGet(i);
       if (likely(obj1.isNum())) m[i] = obj1.getNum();
       else m[i] = 0;
-      obj1.free();
     }
   } else {
     m[0] = 1; m[1] = 0;
     m[2] = 0; m[3] = 1;
     m[4] = 0; m[5] = 0;
   }
-  matrixObj.free();
 
   // get resources
-  dict->lookup("Resources", &resObj);
+  Object resObj = dict->lookup("Resources");
   resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
 
   // check for a transparency group
   transpGroup = isolated = knockout = gFalse;
   blendingColorSpace = NULL;
-  if (dict->lookup("Group", &obj1)->isDict()) {
-    if (obj1.dictLookup("S", &obj2)->isName("Transparency")) {
-      if (!obj1.dictLookup("CS", &obj3)->isNull()) {
+  obj1 = dict->lookup("Group");
+  if (obj1.isDict()) {
+    Object obj2 = obj1.dictLookup("S");
+    if (obj2.isName("Transparency")) {
+      Object obj3 = obj1.dictLookup("CS");
+      if (!obj3.isNull()) {
 	blendingColorSpace = GfxColorSpace::parse(res, &obj3, out, state);
       }
-      obj3.free();
-      if (obj1.dictLookup("I", &obj3)->isBool()) {
+      obj3 = obj1.dictLookup("I");
+      if (obj3.isBool()) {
 	isolated = obj3.getBool();
       }
-      obj3.free();
-      if (obj1.dictLookup("K", &obj3)->isBool()) {
+      obj3 = obj1.dictLookup("K");
+      if (obj3.isBool()) {
 	knockout = obj3.getBool();
       }
-      obj3.free();
       transpGroup = isolated || out->checkTransparencyGroup(state, knockout) || checkTransparencyGroup(resDict);
     }
-    obj2.free();
   }
-  obj1.free();
 
   // draw it
   ++formDepth;
@@ -4900,7 +4736,6 @@ void Gfx::doForm(Object *str) {
   if (blendingColorSpace) {
     delete blendingColorSpace;
   }
-  resObj.free();
 
   ocState = ocSaved;
 }
@@ -5041,45 +4876,37 @@ void Gfx::opBeginImage(Object args[], int numArgs) {
 }
 
 Stream *Gfx::buildImageStream() {
-  Object dict;
-  Object obj;
   char *key;
   Stream *str;
 
   // build dictionary
-  dict.initDict(xref);
-  parser->getObj(&obj);
+  Object dict(new Dict(xref));
+  Object obj = parser->getObj();
   while (!obj.isCmd("ID") && !obj.isEOF()) {
     if (!obj.isName()) {
       error(errSyntaxError, getPos(), "Inline image dictionary key must be a name object");
-      obj.free();
     } else {
       key = copyString(obj.getName());
-      obj.free();
-      parser->getObj(&obj);
+      obj = parser->getObj();
       if (obj.isEOF() || obj.isError()) {
 	gfree(key);
 	break;
       }
-      dict.dictAdd(key, &obj);
+      dict.dictAdd(key, std::move(obj));
     }
-    parser->getObj(&obj);
+    obj = parser->getObj();
   }
   if (obj.isEOF()) {
     error(errSyntaxError, getPos(), "End of file in inline image");
-    obj.free();
-    dict.free();
     return NULL;
   }
-  obj.free();
 
   // make stream
   if (parser->getStream()) {
-    str = new EmbedStream(parser->getStream(), &dict, gFalse, 0);
+    str = new EmbedStream(parser->getStream(), std::move(dict), gFalse, 0);
     str = str->addFilters(str->getDict());
   } else {
     str = NULL;
-    dict.free();
   }
 
   return str;
@@ -5172,27 +4999,25 @@ void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
 	error(errSyntaxError, getPos(), "Unexpected MC Type: {0:d}", args[1].getType());
       }
       char* name1 = args[1].getName();
-      Object markedContent;
       MarkedContentStack *mc = mcStack;
       mc->kind = gfxMCOptionalContent;
-      if ( res->lookupMarkedContentNF( name1, &markedContent ) ) {
+      Object markedContent = res->lookupMarkedContentNF( name1 );
+      if (!markedContent.isNull()) {
         bool visible = contentConfig->optContentIsVisible(&markedContent);
         mc->ocSuppressed = !(visible);
       } else {
 	error(errSyntaxError, getPos(), "DID NOT find {0:s}", name1);
       }
-      markedContent.free();
     } else {
       error(errSyntaxError, getPos(), "insufficient arguments for Marked Content");
     }
   } else if (args[0].isName("Span") && numArgs == 2 && args[1].isDict()) {
-    Object obj;
-    if (args[1].dictLookup("ActualText", &obj)->isString()) {
+    Object obj = args[1].dictLookup("ActualText");
+    if (obj.isString()) {
       out->beginActualText(state, obj.getString());
       MarkedContentStack *mc = mcStack;
       mc->kind = gfxMCActualText;
     }
-    obj.free();
   }
 
   if (printCommands) {
@@ -5266,7 +5091,6 @@ struct GfxStackStateSaver {
 void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor,
 		    double xMin, double yMin, double xMax, double yMax, int rotate) {
   Dict *dict, *resDict;
-  Object matrixObj, bboxObj, resObj, obj1;
   double formXMin, formYMin, formXMax, formYMax;
   double x, y, sx, sy, tx, ty;
   double m[6], bbox[4];
@@ -5314,37 +5138,29 @@ void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor,
     dict = str->streamGetDict();
 
     // get the form bounding box
-    dict->lookup("BBox", &bboxObj);
+    Object bboxObj = dict->lookup("BBox");
     if (!bboxObj.isArray()) {
-      bboxObj.free();
       error(errSyntaxError, getPos(), "Bad form bounding box");
       return;
     }
     for (i = 0; i < 4; ++i) {
-      bboxObj.arrayGet(i, &obj1);
+      Object obj1 = bboxObj.arrayGet(i);
       if (likely(obj1.isNum())) {
         bbox[i] = obj1.getNum();
-        obj1.free();
       } else {
-        obj1.free();
-        bboxObj.free();
         error(errSyntaxError, getPos(), "Bad form bounding box value");
         return;
       }
     }
-    bboxObj.free();
 
     // get the form matrix
-    dict->lookup("Matrix", &matrixObj);
+    Object matrixObj = dict->lookup("Matrix");
     if (matrixObj.isArray() && matrixObj.arrayGetLength() >= 6) {
       for (i = 0; i < 6; ++i) {
-	matrixObj.arrayGet(i, &obj1);
+	Object obj1 = matrixObj.arrayGet(i);
 	if (likely(obj1.isNum())) {
 	  m[i] = obj1.getNum();
-	  obj1.free();
 	} else {
-	  obj1.free();
-	  matrixObj.free();
 	  error(errSyntaxError, getPos(), "Bad form matrix");
 	  return;
 	}
@@ -5354,7 +5170,6 @@ void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor,
       m[2] = 0; m[3] = 1;
       m[4] = 0; m[5] = 0;
     }
-    matrixObj.free();
 
     // transform the four corners of the form bbox to default user
     // space, and construct the transformed bbox
@@ -5427,13 +5242,11 @@ void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor,
     m[5] = m[5] * sy + ty;
 
     // get the resources
-    dict->lookup("Resources", &resObj);
+    Object resObj = dict->lookup("Resources");
     resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
 
     // draw it
     drawForm(str, resDict, m, bbox);
-
-    resObj.free();
   }
 
   // draw the border
diff --git a/poppler/Gfx.h b/poppler/Gfx.h
index a82f9f4a..fe35ad10 100644
--- a/poppler/Gfx.h
+++ b/poppler/Gfx.h
@@ -113,14 +113,14 @@ public:
   ~GfxResources();
 
   GfxFont *lookupFont(char *name);
-  GBool lookupXObject(char *name, Object *obj);
-  GBool lookupXObjectNF(char *name, Object *obj);
-  GBool lookupMarkedContentNF(char *name, Object *obj);
-  void lookupColorSpace(const char *name, Object *obj);
+  Object lookupXObject(char *name);
+  Object lookupXObjectNF(char *name);
+  Object lookupMarkedContentNF(char *name);
+  Object lookupColorSpace(const char *name);
   GfxPattern *lookupPattern(char *name, OutputDev *out, GfxState *state);
   GfxShading *lookupShading(char *name, OutputDev *out, GfxState *state);
-  GBool lookupGState(char *name, Object *obj);
-  GBool lookupGStateNF(char *name, Object *obj);
+  Object lookupGState(char *name);
+  Object lookupGStateNF(char *name);
 
   GfxResources *getNext() { return next; }
 
diff --git a/poppler/GfxFont.cc b/poppler/GfxFont.cc
index ea23e03a..c2f256e0 100644
--- a/poppler/GfxFont.cc
+++ b/poppler/GfxFont.cc
@@ -210,15 +210,13 @@ GfxFont *GfxFont::makeFont(XRef *xref, const char *tagA, Ref idA, Dict *fontDict
   Ref embFontIDA;
   GfxFontType typeA;
   GfxFont *font;
-  Object obj1;
 
   // get base font name
   nameA = NULL;
-  fontDict->lookup("BaseFont", &obj1);
+  Object obj1 = fontDict->lookup("BaseFont");
   if (obj1.isName()) {
     nameA = new GooString(obj1.getName());
   }
-  obj1.free();
 
   // get embedded font ID and font type
   typeA = getFontType(xref, fontDict, &embFontIDA);
@@ -290,14 +288,13 @@ GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) {
   GfxFontType t, expectedType;
   FoFiIdentifierType fft;
   Dict *fontDict2;
-  Object subtype, fontDesc, obj1, obj2, obj3, obj4;
   GBool isType0, err;
 
   t = fontUnknownType;
   embID->num = embID->gen = -1;
   err = gFalse;
 
-  fontDict->lookup("Subtype", &subtype);
+  Object subtype = fontDict->lookup("Subtype");
   expectedType = fontUnknownType;
   isType0 = gFalse;
   if (subtype.isName("Type1") || subtype.isName("MMType1")) {
@@ -314,44 +311,45 @@ GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) {
     error(errSyntaxWarning, -1, "Unknown font type: '{0:s}'",
 	  subtype.isName() ? subtype.getName() : "???");
   }
-  subtype.free();
 
   fontDict2 = fontDict;
-  if (fontDict->lookup("DescendantFonts", &obj1)->isArray()) {
+  Object obj1 = fontDict->lookup("DescendantFonts");
+  Object obj2; // Do not move to inside the if
+               // we need it around so that fontDict2 remains valid
+  if (obj1.isArray()) {
     if (obj1.arrayGetLength() == 0) {
       error(errSyntaxWarning, -1, "Empty DescendantFonts array in font");
-      obj2.initNull();
-    } else if (obj1.arrayGet(0, &obj2)->isDict()) {
-      if (!isType0) {
-	error(errSyntaxWarning, -1, "Non-CID font with DescendantFonts array");
-      }
-      fontDict2 = obj2.getDict();
-      fontDict2->lookup("Subtype", &subtype);
-      if (subtype.isName("CIDFontType0")) {
-	if (isType0) {
-	  expectedType = fontCIDType0;
+    } else {
+      obj2 = obj1.arrayGet(0);
+      if (obj2.isDict()) {
+	if (!isType0) {
+	  error(errSyntaxWarning, -1, "Non-CID font with DescendantFonts array");
 	}
-      } else if (subtype.isName("CIDFontType2")) {
-	if (isType0) {
-	  expectedType = fontCIDType2;
+	fontDict2 = obj2.getDict();
+	subtype = fontDict2->lookup("Subtype");
+	if (subtype.isName("CIDFontType0")) {
+	  if (isType0) {
+	    expectedType = fontCIDType0;
+	  }
+	} else if (subtype.isName("CIDFontType2")) {
+	  if (isType0) {
+	    expectedType = fontCIDType2;
+	  }
 	}
       }
-      subtype.free();
     }
-  } else {
-    obj2.initNull();
   }
 
-  if (fontDict2->lookup("FontDescriptor", &fontDesc)->isDict()) {
-    if (fontDesc.dictLookupNF("FontFile", &obj3)->isRef()) {
+  Object fontDesc = fontDict2->lookup("FontDescriptor");
+  if (fontDesc.isDict()) {
+    Object obj3 = fontDesc.dictLookupNF("FontFile");
+    if (obj3.isRef()) {
       *embID = obj3.getRef();
       if (expectedType != fontType1) {
 	err = gTrue;
       }
     }
-    obj3.free();
-    if (embID->num == -1 &&
-	fontDesc.dictLookupNF("FontFile2", &obj3)->isRef()) {
+    if (embID->num == -1 && (obj3 = fontDesc.dictLookupNF("FontFile2"), obj3.isRef())) {
       *embID = obj3.getRef();
       if (isType0) {
 	expectedType = fontCIDType2;
@@ -359,12 +357,11 @@ GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) {
 	err = gTrue;
       }
     }
-    obj3.free();
-    if (embID->num == -1 &&
-	fontDesc.dictLookupNF("FontFile3", &obj3)->isRef()) {
+    if (embID->num == -1 && (obj3 = fontDesc.dictLookupNF("FontFile3"), obj3.isRef())) {
       *embID = obj3.getRef();
-      if (obj3.fetch(xref, &obj4)->isStream()) {
-	obj4.streamGetDict()->lookup("Subtype", &subtype);
+      Object obj4 = obj3.fetch(xref);
+      if (obj4.isStream()) {
+	subtype = obj4.streamGetDict()->lookup("Subtype");
 	if (subtype.isName("Type1")) {
 	  if (expectedType != fontType1) {
 	    err = gTrue;
@@ -405,18 +402,14 @@ GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) {
 	  error(errSyntaxError, -1, "Unknown font type '{0:s}'",
 		subtype.isName() ? subtype.getName() : "???");
 	}
-	subtype.free();
       }
-      obj4.free();
     }
-    obj3.free();
   }
-  fontDesc.free();
 
   t = fontUnknownType;
   if (embID->num >= 0) {
-    obj3.initRef(embID->num, embID->gen);
-    obj3.fetch(xref, &obj4);
+    Object obj3(embID->num, embID->gen);
+    Object obj4 = obj3.fetch(xref);
     if (obj4.isStream()) {
       obj4.streamReset();
       fft = FoFiIdentifier::identifyStream(&readFromStream, obj4.getStream());
@@ -447,8 +440,6 @@ GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) {
 	break;
       }
     }
-    obj4.free();
-    obj3.free();
   }
 
   if (t == fontUnknownType) {
@@ -464,53 +455,46 @@ GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) {
 	  "Mismatch between font type and embedded font file");
   }
 
-  obj2.free();
-  obj1.free();
-
   return t;
 }
 
 void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
-  Object obj1, obj2, obj3, obj4;
   double t;
-  int i;
 
   // assume Times-Roman by default (for substitution purposes)
   flags = fontSerif;
 
   missingWidth = 0;
 
-  if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) {
+  Object obj1 = fontDict->lookup("FontDescriptor");
+  if (obj1.isDict()) {
 
     // get flags
-    if (obj1.dictLookup("Flags", &obj2)->isInt()) {
+    Object obj2 = obj1.dictLookup("Flags");
+    if (obj2.isInt()) {
       flags = obj2.getInt();
     }
-    obj2.free();
 
     // get name
-    obj1.dictLookup("FontName", &obj2);
+    obj2 = obj1.dictLookup("FontName");
     if (obj2.isName()) {
       embFontName = new GooString(obj2.getName());
     }
-    obj2.free();
     if (embFontName == NULL) {
       // get name with typo
-      obj1.dictLookup("Fontname", &obj2);
+      obj2 = obj1.dictLookup("Fontname");
       if (obj2.isName()) {
         embFontName = new GooString(obj2.getName());
         error(errSyntaxWarning, -1, "The file uses Fontname instead of FontName please notify the creator that the file is broken");
       }
-      obj2.free();
     }
 
     // get family
-    obj1.dictLookup("FontFamily", &obj2);
+    obj2 = obj1.dictLookup("FontFamily");
     if (obj2.isString()) family = new GooString(obj2.getString());
-    obj2.free();
 
     // get stretch
-    obj1.dictLookup("FontStretch", &obj2);
+    obj2 = obj1.dictLookup("FontStretch");
     if (obj2.isName()) {
       if (strcmp(obj2.getName(), "UltraCondensed") == 0) stretch = UltraCondensed;
       else if (strcmp(obj2.getName(), "ExtraCondensed") == 0) stretch = ExtraCondensed;
@@ -523,10 +507,9 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
       else if (strcmp(obj2.getName(), "UltraExpanded") == 0) stretch = UltraExpanded;
       else error(errSyntaxWarning, -1, "Invalid Font Stretch");
     }
-    obj2.free();
     
     // get weight
-    obj1.dictLookup("FontWeight", &obj2);
+    obj2 = obj1.dictLookup("FontWeight");
     if (obj2.isNum()) {
       if (obj2.getNum() == 100) weight = W100;
       else if (obj2.getNum() == 200) weight = W200;
@@ -539,17 +522,15 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
       else if (obj2.getNum() == 900) weight = W900;
       else error(errSyntaxWarning, -1, "Invalid Font Weight");
     }
-    obj2.free();
 
     // look for MissingWidth
-    obj1.dictLookup("MissingWidth", &obj2);
+    obj2 = obj1.dictLookup("MissingWidth");
     if (obj2.isNum()) {
       missingWidth = obj2.getNum();
     }
-    obj2.free();
 
     // get Ascent and Descent
-    obj1.dictLookup("Ascent", &obj2);
+    obj2 = obj1.dictLookup("Ascent");
     if (obj2.isNum()) {
       t = 0.001 * obj2.getNum();
       // some broken font descriptors specify a negative ascent
@@ -562,8 +543,7 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
 	ascent = t;
       }
     }
-    obj2.free();
-    obj1.dictLookup("Descent", &obj2);
+    obj2 = obj1.dictLookup("Descent");
     if (obj2.isNum()) {
       t = 0.001 * obj2.getNum();
       // some broken font descriptors specify a positive descent
@@ -575,36 +555,31 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
 	descent = t;
       }
     }
-    obj2.free();
 
     // font FontBBox
-    if (obj1.dictLookup("FontBBox", &obj2)->isArray()) {
-      for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) {
-	if (obj2.arrayGet(i, &obj3)->isNum()) {
+    obj2 = obj1.dictLookup("FontBBox");
+    if (obj2.isArray()) {
+      for (int i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) {
+	Object obj3 = obj2.arrayGet(i);
+	if (obj3.isNum()) {
 	  fontBBox[i] = 0.001 * obj3.getNum();
 	}
-	obj3.free();
       }
     }
-    obj2.free();
-
   }
-  obj1.free();
 }
 
 CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits,
 					      CharCodeToUnicode *ctu) {
   GooString *buf;
-  Object obj1;
 
-  if (!fontDict->lookup("ToUnicode", &obj1)->isStream()) {
-    obj1.free();
+  Object obj1 = fontDict->lookup("ToUnicode");
+  if (!obj1.isStream()) {
     return NULL;
   }
   buf = new GooString();
   obj1.getStream()->fillGooString(buf);
   obj1.streamClose();
-  obj1.free();
   if (ctu) {
     ctu->mergeCMap(buf, nBits);
   } else {
@@ -620,7 +595,6 @@ GfxFontLoc *GfxFont::locateFont(XRef *xref, PSOutputDev *ps) {
   SysFontType sysFontType;
   GooString *path, *base14Name, *substName;
   PSFontParam16 *psFont16;
-  Object refObj, embFontObj;
   int substIdx, fontNum;
   GBool embed;
 
@@ -631,14 +605,12 @@ GfxFontLoc *GfxFont::locateFont(XRef *xref, PSOutputDev *ps) {
   //----- embedded font
   if (embFontID.num >= 0) {
     embed = gTrue;
-    refObj.initRef(embFontID.num, embFontID.gen);
-    refObj.fetch(xref, &embFontObj);
+    Object refObj(embFontID.num, embFontID.gen);
+    Object embFontObj = refObj.fetch(xref);
     if (!embFontObj.isStream()) {
       error(errSyntaxError, -1, "Embedded font object is wrong type");
       embed = gFalse;
     }
-    embFontObj.free();
-    refObj.free();
     if (embed) {
       if (ps) {
 	switch (type) {
@@ -894,15 +866,12 @@ GfxFontLoc *GfxFont::getExternalFont(GooString *path, GBool cid) {
 
 char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
   char *buf;
-  Object obj1, obj2;
   Stream *str;
 
-  obj1.initRef(embFontID.num, embFontID.gen);
-  obj1.fetch(xref, &obj2);
+  Object obj1(embFontID.num, embFontID.gen);
+  Object obj2 = obj1.fetch(xref);
   if (!obj2.isStream()) {
     error(errSyntaxError, -1, "Embedded font file is not a stream");
-    obj2.free();
-    obj1.free();
     embFontID.num = -1;
     *len = 0;
     return NULL;
@@ -912,9 +881,6 @@ char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
   buf = (char*)str->toUnsignedChars(len);
   str->close();
 
-  obj2.free();
-  obj1.free();
-
   return buf;
 }
 
@@ -995,24 +961,20 @@ static GBool parseNumericName(char *s, GBool hex, unsigned int *u) {
 // Returns gTrue if the font has character names like xx or Axx which
 // should be parsed for hex or decimal values.
 static GBool testForNumericNames(Dict *fontDict, GBool hex) {
-  Object enc, diff, obj;
   GBool numeric = gTrue;
 
-  fontDict->lookup("Encoding", &enc);
+  Object enc = fontDict->lookup("Encoding");
   if (!enc.isDict()) {
-    enc.free();
     return gFalse;
   }
 
-  enc.dictLookup("Differences", &diff);
-  enc.free();
+  Object diff = enc.dictLookup("Differences");
   if (!diff.isArray()) {
-    diff.free();
     return gFalse;
   }
 
   for (int i = 0; i < diff.arrayGetLength() && numeric; ++i) {
-    diff.arrayGet(i, &obj);
+    Object obj = diff.arrayGet(i);
     if (obj.isInt()) {
       // All sequences must start between character codes 0 and 5.
       if (obj.getInt() > 5)
@@ -1024,10 +986,8 @@ static GBool testForNumericNames(Dict *fontDict, GBool hex) {
     } else {
       numeric = gFalse;
     }
-    obj.free();
   }
 
-  diff.free();
   return numeric;
 }
 
@@ -1052,7 +1012,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA
   double mul;
   int firstChar, lastChar;
   Gushort w;
-  Object obj1, obj2, obj3;
+  Object obj1;
   int n, i, a, b, m;
 
   refCnt = 1;
@@ -1130,34 +1090,36 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA
   // get font matrix
   fontMat[0] = fontMat[3] = 1;
   fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
-  if (fontDict->lookup("FontMatrix", &obj1)->isArray()) {
+  obj1 = fontDict->lookup("FontMatrix");
+  if (obj1.isArray()) {
     for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) {
-      if (obj1.arrayGet(i, &obj2)->isNum()) {
+      Object obj2 = obj1.arrayGet(i);
+      if (obj2.isNum()) {
 	fontMat[i] = obj2.getNum();
       }
-      obj2.free();
     }
   }
-  obj1.free();
 
   // get Type 3 bounding box, font definition, and resources
   if (type == fontType3) {
-    if (fontDict->lookup("FontBBox", &obj1)->isArray()) {
+    obj1 = fontDict->lookup("FontBBox");
+    if (obj1.isArray()) {
       for (i = 0; i < 4 && i < obj1.arrayGetLength(); ++i) {
-	if (obj1.arrayGet(i, &obj2)->isNum()) {
+	Object obj2 = obj1.arrayGet(i);
+	if (obj2.isNum()) {
 	  fontBBox[i] = obj2.getNum();
 	}
-	obj2.free();
       }
     }
-    obj1.free();
-    if (!fontDict->lookup("CharProcs", &charProcs)->isDict()) {
+    charProcs = fontDict->lookup("CharProcs");
+    if (!charProcs.isDict()) {
       error(errSyntaxError, -1,
 	    "Missing or invalid CharProcs dictionary in Type 3 font");
-      charProcs.free();
+      charProcs.setToNull();
     }
-    if (!fontDict->lookup("Resources", &resources)->isDict()) {
-      resources.free();
+    resources = fontDict->lookup("Resources");
+    if (!resources.isDict()) {
+      resources.setToNull();
     }
   }
 
@@ -1180,9 +1142,9 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA
   usesMacRomanEnc = gFalse;
   baseEnc = NULL;
   baseEncFromFontFile = gFalse;
-  fontDict->lookup("Encoding", &obj1);
+  obj1 = fontDict->lookup("Encoding");
   if (obj1.isDict()) {
-    obj1.dictLookup("BaseEncoding", &obj2);
+    Object obj2 = obj1.dictLookup("BaseEncoding");
     if (obj2.isName("MacRomanEncoding")) {
       hasEncoding = gTrue;
       usesMacRomanEnc = gTrue;
@@ -1194,7 +1156,6 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA
       hasEncoding = gTrue;
       baseEnc = winAnsiEncoding;
     }
-    obj2.free();
   } else if (obj1.isName("MacRomanEncoding")) {
     hasEncoding = gTrue;
     usesMacRomanEnc = gTrue;
@@ -1298,13 +1259,13 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA
 
   // merge differences into encoding
   if (obj1.isDict()) {
-    obj1.dictLookup("Differences", &obj2);
+    Object obj2 = obj1.dictLookup("Differences");
     if (obj2.isArray()) {
       encodingName->Set("Custom");
       hasEncoding = gTrue;
       code = 0;
       for (i = 0; i < obj2.arrayGetLength(); ++i) {
-	obj2.arrayGet(i, &obj3);
+	Object obj3 = obj2.arrayGet(i);
 	if (obj3.isInt()) {
 	  code = obj3.getInt();
 	} else if (obj3.isName()) {
@@ -1321,18 +1282,11 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA
 		"Wrong type in font encoding resource differences ({0:s})",
 		obj3.getTypeName());
 	}
-	obj3.free();
       }
     }
-    obj2.free();
-  }
-  obj1.free();
-  if (ffT1) {
-    delete ffT1;
-  }
-  if (ffT1C) {
-    delete ffT1C;
   }
+  delete ffT1;
+  delete ffT1C;
 
   //----- build the mapping to Unicode -----
 
@@ -1450,34 +1404,31 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA
   }
 
   // use widths from font dict, if present
-  fontDict->lookup("FirstChar", &obj1);
+  obj1 = fontDict->lookup("FirstChar");
   firstChar = obj1.isInt() ? obj1.getInt() : 0;
-  obj1.free();
   if (firstChar < 0 || firstChar > 255) {
     firstChar = 0;
   }
-  fontDict->lookup("LastChar", &obj1);
+  obj1 = fontDict->lookup("LastChar");
   lastChar = obj1.isInt() ? obj1.getInt() : 255;
-  obj1.free();
   if (lastChar < 0 || lastChar > 255) {
     lastChar = 255;
   }
   mul = (type == fontType3) ? fontMat[0] : 0.001;
-  fontDict->lookup("Widths", &obj1);
+  obj1 = fontDict->lookup("Widths");
   if (obj1.isArray()) {
     flags |= fontFixedWidth;
     if (obj1.arrayGetLength() < lastChar - firstChar + 1) {
       lastChar = firstChar + obj1.arrayGetLength() - 1;
     }
     for (code = firstChar; code <= lastChar; ++code) {
-      obj1.arrayGet(code - firstChar, &obj2);
+      Object obj2 = obj1.arrayGet(code - firstChar);
       if (obj2.isNum()) {
 	widths[code] = obj2.getNum() * mul;
 	if (fabs(widths[code] - widths[firstChar]) > 0.00001) {
 	  flags &= ~fontFixedWidth;
 	}
       }
-      obj2.free();
     }
 
   // use widths from built-in font
@@ -1523,7 +1474,6 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA
       }
     }
   }
-  obj1.free();
 
   ok = gTrue;
 }
@@ -1537,12 +1487,6 @@ Gfx8BitFont::~Gfx8BitFont() {
     }
   }
   ctu->decRefCnt();
-  if (charProcs.isDict()) {
-    charProcs.free();
-  }
-  if (resources.isDict()) {
-    resources.free();
-  }
 }
 
 // This function is in part a derived work of the Adobe Glyph Mapping
@@ -1809,13 +1753,12 @@ Dict *Gfx8BitFont::getCharProcs() {
   return charProcs.isDict() ? charProcs.getDict() : (Dict *)NULL;
 }
 
-Object *Gfx8BitFont::getCharProc(int code, Object *proc) {
+Object Gfx8BitFont::getCharProc(int code) {
   if (enc[code] && charProcs.isDict()) {
-    charProcs.dictLookup(enc[code], proc);
+    return charProcs.dictLookup(enc[code]);
   } else {
-    proc->initNull();
+    return Object(objNull);
   }
-  return proc;
 }
 
 Dict *Gfx8BitFont::getResources() {
@@ -1872,17 +1815,16 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
   cidToGIDLen = 0;
 
   // get the descendant font
-  if (!fontDict->lookup("DescendantFonts", &obj1)->isArray() ||
-      obj1.arrayGetLength() == 0) {
+  obj1 = fontDict->lookup("DescendantFonts");
+  if (!obj1.isArray() || obj1.arrayGetLength() == 0) {
     error(errSyntaxError, -1, "Missing or empty DescendantFonts entry in Type 0 font");
-    obj1.free();
-    goto err1;
+    return;
   }
-  if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) {
+  desFontDictObj = obj1.arrayGet(0);
+  if (!desFontDictObj.isDict()) {
     error(errSyntaxError, -1, "Bad descendant font in Type 0 font");
-    goto err3;
+    return;
   }
-  obj1.free();
   desFontDict = desFontDictObj.getDict();
 
   // get info from font descriptor
@@ -1891,20 +1833,18 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
   //----- encoding info -----
 
   // char collection
-  if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) {
+  obj1 = desFontDict->lookup("CIDSystemInfo");
+  if (!obj1.isDict()) {
     error(errSyntaxError, -1, "Missing CIDSystemInfo dictionary in Type 0 descendant font");
-    goto err3;
+    return;
   }
-  obj1.dictLookup("Registry", &obj2);
-  obj1.dictLookup("Ordering", &obj3);
+  obj2 = obj1.dictLookup("Registry");
+  obj3 = obj1.dictLookup("Ordering");
   if (!obj2.isString() || !obj3.isString()) {
     error(errSyntaxError, -1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font");
-    goto err3;
+    return;
   }
   collection = obj2.getString()->copy()->append('-')->append(obj3.getString());
-  obj3.free();
-  obj2.free();
-  obj1.free();
 
   // look for a ToUnicode CMap
   if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) {
@@ -1933,7 +1873,7 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
 	for (size_t i = 0; i < sizeof(knownCollections)/sizeof(knownCollections[0]); i++) {
 	  if (collection->cmp(knownCollections[i]) == 0) {
 	    error(errSyntaxError, -1, "Missing language pack for '{0:t}' mapping", collection);
-	    goto err2;
+	    return;
 	  }
 	}
 	error(errSyntaxError, -1, "Unknown character collection '{0:t}'",
@@ -1963,14 +1903,14 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
   }
 
   // encoding (i.e., CMap)
-  if (fontDict->lookup("Encoding", &obj1)->isNull()) {
+  obj1 = fontDict->lookup("Encoding");
+  if (obj1.isNull()) {
     error(errSyntaxError, -1, "Missing Encoding entry in Type 0 font");
-    goto err2;
+    return;
   }
   if (!(cMap = CMap::parse(NULL, collection, &obj1))) {
-    goto err2;
+    return;
   }
-  obj1.free();
   if (cMap->getCMapName()) {
     encodingName->Set(cMap->getCMapName()->getCString());
   } else {
@@ -1979,7 +1919,7 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
 
   // CIDToGIDMap (for embedded TrueType fonts)
   if (type == fontCIDType2 || type == fontCIDType2OT) {
-    desFontDict->lookup("CIDToGIDMap", &obj1);
+    obj1 = desFontDict->lookup("CIDToGIDMap");
     if (obj1.isStream()) {
       cidToGIDLen = 0;
       i = 64;
@@ -1996,26 +1936,27 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
     } else if (!obj1.isName("Identity") && !obj1.isNull()) {
       error(errSyntaxError, -1, "Invalid CIDToGIDMap entry in CID font");
     }
-    obj1.free();
   }
 
   //----- character metrics -----
 
   // default char width
-  if (desFontDict->lookup("DW", &obj1)->isInt()) {
+  obj1 = desFontDict->lookup("DW");
+  if (obj1.isInt()) {
     widths.defWidth = obj1.getInt() * 0.001;
   }
-  obj1.free();
 
   // char width exceptions
-  if (desFontDict->lookup("W", &obj1)->isArray()) {
+  obj1 = desFontDict->lookup("W");
+  if (obj1.isArray()) {
     excepsSize = 0;
     i = 0;
     while (i + 1 < obj1.arrayGetLength()) {
-      obj1.arrayGet(i, &obj2);
-      obj1.arrayGet(i + 1, &obj3);
+      obj2 = obj1.arrayGet(i);
+      obj3 = obj1.arrayGet(i + 1);
       if (obj2.isInt() && obj3.isInt() && i + 2 < obj1.arrayGetLength()) {
-	if (obj1.arrayGet(i + 2, &obj4)->isNum()) {
+	obj4 = obj1.arrayGet(i + 2);
+	if (obj4.isNum()) {
 	  if (widths.nExceps == excepsSize) {
 	    excepsSize += 16;
 	    widths.exceps = (GfxFontCIDWidthExcep *)
@@ -2029,7 +1970,6 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
 	} else {
 	  error(errSyntaxError, -1, "Bad widths array in Type 0 font");
 	}
-	obj4.free();
 	i += 3;
       } else if (obj2.isInt() && obj3.isArray()) {
 	if (widths.nExceps + obj3.arrayGetLength() > excepsSize) {
@@ -2040,7 +1980,8 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
 	}
 	j = obj2.getInt();
 	for (k = 0; k < obj3.arrayGetLength(); ++k) {
-	  if (obj3.arrayGet(k, &obj4)->isNum()) {
+	  obj4 = obj3.arrayGet(k);
+	  if (obj4.isNum()) {
 	    widths.exceps[widths.nExceps].first = j;
 	    widths.exceps[widths.nExceps].last = j;
 	    widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001;
@@ -2049,46 +1990,43 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
 	  } else {
 	    error(errSyntaxError, -1, "Bad widths array in Type 0 font");
 	  }
-	  obj4.free();
 	}
 	i += 2;
       } else {
 	error(errSyntaxError, -1, "Bad widths array in Type 0 font");
 	++i;
       }
-      obj3.free();
-      obj2.free();
     }
     std::sort(widths.exceps, widths.exceps + widths.nExceps,
 	      cmpWidthExcepFunctor());
   }
-  obj1.free();
 
   // default metrics for vertical font
-  if (desFontDict->lookup("DW2", &obj1)->isArray() &&
+  obj1 = desFontDict->lookup("DW2");
+  if (obj1.isArray() &&
       obj1.arrayGetLength() == 2) {
-    if (obj1.arrayGet(0, &obj2)->isNum()) {
+    obj2 = obj1.arrayGet(0);
+    if (obj2.isNum()) {
       widths.defVY = obj2.getNum() * 0.001;
     }
-    obj2.free();
-    if (obj1.arrayGet(1, &obj2)->isNum()) {
+    obj2 = obj1.arrayGet(1);
+    if (obj2.isNum()) {
       widths.defHeight = obj2.getNum() * 0.001;
     }
-    obj2.free();
   }
-  obj1.free();
 
   // char metric exceptions for vertical font
-  if (desFontDict->lookup("W2", &obj1)->isArray()) {
+  obj1 = desFontDict->lookup("W2");
+  if (obj1.isArray()) {
     excepsSize = 0;
     i = 0;
     while (i + 1 < obj1.arrayGetLength()) {
-      obj1.arrayGet(i, &obj2);
-      obj1.arrayGet(i+ 1, &obj3);
+      obj2 = obj1.arrayGet(i);
+      obj3 = obj1.arrayGet(i+ 1);
       if (obj2.isInt() && obj3.isInt() && i + 4 < obj1.arrayGetLength()) {
-	if (obj1.arrayGet(i + 2, &obj4)->isNum() &&
-	    obj1.arrayGet(i + 3, &obj5)->isNum() &&
-	    obj1.arrayGet(i + 4, &obj6)->isNum()) {
+	if ((obj4 = obj1.arrayGet(i + 2), obj4.isNum()) &&
+	    (obj5 = obj1.arrayGet(i + 3), obj5.isNum()) &&
+	    (obj6 = obj1.arrayGet(i + 4), obj6.isNum())) {
 	  if (widths.nExcepsV == excepsSize) {
 	    excepsSize += 16;
 	    widths.excepsV = (GfxFontCIDWidthExcepV *)
@@ -2104,9 +2042,6 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
 	} else {
 	  error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font");
 	}
-	obj6.free();
-	obj5.free();
-	obj4.free();
 	i += 5;
       } else if (obj2.isInt() && obj3.isArray()) {
 	if (widths.nExcepsV + obj3.arrayGetLength() / 3 > excepsSize) {
@@ -2118,9 +2053,9 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
 	}
 	j = obj2.getInt();
 	for (k = 0; k < obj3.arrayGetLength(); k += 3) {
-	  if (obj3.arrayGet(k, &obj4)->isNum() &&
-	      obj3.arrayGet(k+1, &obj5)->isNum() &&
-	      obj3.arrayGet(k+2, &obj6)->isNum()) {
+	  if ((obj4 = obj3.arrayGet(k), obj4.isNum()) &&
+	      (obj5 = obj3.arrayGet(k+1), obj5.isNum()) &&
+	      (obj6 = obj3.arrayGet(k+2), obj6.isNum())) {
 	    widths.excepsV[widths.nExcepsV].first = j;
 	    widths.excepsV[widths.nExcepsV].last = j;
 	    widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001;
@@ -2131,34 +2066,18 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
 	  } else {
 	    error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font");
 	  }
-	  obj6.free();
-	  obj5.free();
-	  obj4.free();
 	}
 	i += 2;
       } else {
 	error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font");
 	++i;
       }
-      obj3.free();
-      obj2.free();
     }
     std::sort(widths.excepsV, widths.excepsV + widths.nExcepsV,
 	      cmpWidthExcepVFunctor());
   }
-  obj1.free();
 
-  desFontDictObj.free();
   ok = gTrue;
-  return;
-
- err3:
-  obj3.free();
-  obj2.free();
- err2:
-  obj1.free();
-  desFontDictObj.free();
- err1:;
 }
 
 GfxCIDFont::~GfxCIDFont() {
@@ -2560,14 +2479,13 @@ double GfxCIDFont::getWidth (char* s, int len) {
 
 GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) {
   int i;
-  Object obj1, obj2;
   Ref r;
 
   numFonts = fontDict->getLength();
   fonts = (GfxFont **)gmallocn(numFonts, sizeof(GfxFont *));
   for (i = 0; i < numFonts; ++i) {
-    fontDict->getValNF(i, &obj1);
-    obj1.fetch(xref, &obj2);
+    Object obj1 = fontDict->getValNF(i);
+    Object obj2 = obj1.fetch(xref);
     if (obj2.isDict()) {
       if (obj1.isRef()) {
 	r = obj1.getRef();
@@ -2596,8 +2514,6 @@ GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) {
       error(errSyntaxError, -1, "font resource is not a dictionary");
       fonts[i] = NULL;
     }
-    obj1.free();
-    obj2.free();
   }
 }
 
diff --git a/poppler/GfxFont.h b/poppler/GfxFont.h
index de7a7464..de767e79 100644
--- a/poppler/GfxFont.h
+++ b/poppler/GfxFont.h
@@ -352,7 +352,7 @@ public:
   Dict *getCharProcs();
 
   // Return the Type 3 CharProc for the character associated with <code>.
-  Object *getCharProc(int code, Object *proc);
+  Object getCharProc(int code);
 
   // Return the Type 3 Resources dictionary, or NULL if none.
   Dict *getResources();
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 2c81dfbe..61b462a8 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -314,40 +314,34 @@ GfxColorSpace *GfxColorSpace::parse(GfxResources *res, Object *csObj, OutputDev
   if (csObj->isName()) {
     if (csObj->isName("DeviceGray") || csObj->isName("G")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultGray", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultGray");
         if (objCS.isNull()) {
           cs = new GfxDeviceGrayColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceGrayColorSpace();
       }
     } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultRGB", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultRGB");
         if (objCS.isNull()) {
           cs = new GfxDeviceRGBColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceRGBColorSpace();
       }
     } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultCMYK", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultCMYK");
         if (objCS.isNull()) {
           cs = new GfxDeviceCMYKColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceCMYKColorSpace();
       }
@@ -357,43 +351,37 @@ GfxColorSpace *GfxColorSpace::parse(GfxResources *res, Object *csObj, OutputDev
       error(errSyntaxWarning, -1, "Bad color space '{0:s}'", csObj->getName());
     }
   } else if (csObj->isArray() && csObj->arrayGetLength() > 0) {
-    csObj->arrayGet(0, &obj1);
+    obj1 = csObj->arrayGet(0);
     if (obj1.isName("DeviceGray") || obj1.isName("G")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultGray", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultGray");
         if (objCS.isNull()) {
           cs = new GfxDeviceGrayColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceGrayColorSpace();
       }
     } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultRGB", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultRGB");
         if (objCS.isNull()) {
           cs = new GfxDeviceRGBColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceRGBColorSpace();
       }
     } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultCMYK", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultCMYK");
         if (objCS.isNull()) {
           cs = new GfxDeviceCMYKColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceCMYKColorSpace();
       }
@@ -416,52 +404,44 @@ GfxColorSpace *GfxColorSpace::parse(GfxResources *res, Object *csObj, OutputDev
     } else {
       error(errSyntaxWarning, -1, "Bad color space");
     }
-    obj1.free();
   } else if (csObj->isDict()) {
-    csObj->dictLookup("ColorSpace", &obj1);
+    obj1 = csObj->dictLookup("ColorSpace");
     if (obj1.isName("DeviceGray")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultGray", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultGray");
         if (objCS.isNull()) {
           cs = new GfxDeviceGrayColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceGrayColorSpace();
       }
     } else if (obj1.isName("DeviceRGB")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultRGB", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultRGB");
         if (objCS.isNull()) {
           cs = new GfxDeviceRGBColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceRGBColorSpace();
       }
     } else if (obj1.isName("DeviceCMYK")) {
       if (res != NULL) {
-        Object objCS;
-        res->lookupColorSpace("DefaultCMYK", &objCS);
+        Object objCS = res->lookupColorSpace("DefaultCMYK");
         if (objCS.isNull()) {
           cs = new GfxDeviceCMYKColorSpace();
         } else {
           cs = GfxColorSpace::parse(NULL, &objCS, out, state);
         }
-        objCS.free();
       } else {
         cs = new GfxDeviceCMYKColorSpace();
       }
     } else {
       error(errSyntaxWarning, -1, "Bad color space dict'");
     }
-    obj1.free();
   } else {
     error(errSyntaxWarning, -1, "Bad color space - expected name or array or dict");
   }
@@ -830,52 +810,42 @@ static const double xyzrgb[3][3] = {
 
 GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr, GfxState *state) {
   GfxCalGrayColorSpace *cs;
-  Object obj1, obj2, obj3;
+  Object obj1, obj2;
 
-  arr->get(1, &obj1);
+  obj1 = arr->get(1);
   if (!obj1.isDict()) {
     error(errSyntaxWarning, -1, "Bad CalGray color space");
-    obj1.free();
     return NULL;
   }
   cs = new GfxCalGrayColorSpace();
-  if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 3) {
-    obj2.arrayGet(0, &obj3);
+  obj2 = obj1.dictLookup("WhitePoint");
+  if (obj2.isArray() && obj2.arrayGetLength() == 3) {
+    Object obj3 = obj2.arrayGet(0);
     if (likely(obj3.isNum()))
       cs->whiteX = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(1, &obj3);
+    obj3 = obj2.arrayGet(1);
     if (likely(obj3.isNum()))
       cs->whiteY = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(2, &obj3);
+    obj3 = obj2.arrayGet(2);
     if (likely(obj3.isNum()))
       cs->whiteZ = obj3.getNum();
-    obj3.free();
   }
-  obj2.free();
-  if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 3) {
-    obj2.arrayGet(0, &obj3);
+  obj2 = obj1.dictLookup("BlackPoint");
+  if (obj2.isArray() && obj2.arrayGetLength() == 3) {
+    Object obj3 = obj2.arrayGet(0);
     if (likely(obj3.isNum()))
       cs->blackX = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(1, &obj3);
+    obj3 = obj2.arrayGet(1);
     if (likely(obj3.isNum()))
       cs->blackY = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(2, &obj3);
+    obj3 = obj2.arrayGet(2);
     if (likely(obj3.isNum()))
       cs->blackZ = obj3.getNum();
-    obj3.free();
   }
-  obj2.free();
-  if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
+  obj2 = obj1.dictLookup("Gamma");
+  if (obj2.isNum()) {
     cs->gamma = obj2.getNum();
   }
-  obj2.free();
-  obj1.free();
 
   cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
 		xyzrgb[0][1] * cs->whiteY +
@@ -1209,75 +1179,59 @@ GfxColorSpace *GfxCalRGBColorSpace::copy() {
 
 GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr, GfxState *state) {
   GfxCalRGBColorSpace *cs;
-  Object obj1, obj2, obj3;
+  Object obj1, obj2;
   int i;
 
-  arr->get(1, &obj1);
+  obj1 = arr->get(1);
   if (!obj1.isDict()) {
     error(errSyntaxWarning, -1, "Bad CalRGB color space");
-    obj1.free();
     return NULL;
   }
   cs = new GfxCalRGBColorSpace();
-  if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 3) {
-    obj2.arrayGet(0, &obj3);
+  obj2 = obj1.dictLookup("WhitePoint");
+  if (obj2.isArray() && obj2.arrayGetLength() == 3) {
+    Object obj3 = obj2.arrayGet(0);
     if (likely(obj3.isNum()))
       cs->whiteX = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(1, &obj3);
+    obj3 = obj2.arrayGet(1);
     if (likely(obj3.isNum()))
       cs->whiteY = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(2, &obj3);
+    obj3 = obj2.arrayGet(2);
     if (likely(obj3.isNum()))
       cs->whiteZ = obj3.getNum();
-    obj3.free();
   }
-  obj2.free();
-  if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 3) {
-    obj2.arrayGet(0, &obj3);
+  obj2 = obj1.dictLookup("BlackPoint");
+  if (obj2.isArray() && obj2.arrayGetLength() == 3) {
+    Object obj3 = obj2.arrayGet(0);
     if (likely(obj3.isNum()))
       cs->blackX = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(1, &obj3);
+    obj3 = obj2.arrayGet(1);
     if (likely(obj3.isNum()))
       cs->blackY = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(2, &obj3);
+    obj3 = obj2.arrayGet(2);
     if (likely(obj3.isNum()))
       cs->blackZ = obj3.getNum();
-    obj3.free();
   }
-  obj2.free();
-  if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 3) {
-    obj2.arrayGet(0, &obj3);
+  obj2 = obj1.dictLookup("Gamma");
+  if (obj2.isArray() && obj2.arrayGetLength() == 3) {
+    Object obj3 = obj2.arrayGet(0);
     if (likely(obj3.isNum()))
       cs->gammaR = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(1, &obj3);
+    obj3 = obj2.arrayGet(1);
     if (likely(obj3.isNum()))
       cs->gammaG = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(2, &obj3);
+    obj3 = obj2.arrayGet(2);
     if (likely(obj3.isNum()))
       cs->gammaB = obj3.getNum();
-    obj3.free();
   }
-  obj2.free();
-  if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 9) {
+  obj2 = obj1.dictLookup("Matrix");
+  if (obj2.isArray() && obj2.arrayGetLength() == 9) {
     for (i = 0; i < 9; ++i) {
-      obj2.arrayGet(i, &obj3);
+      Object obj3 = obj2.arrayGet(i);
       if (likely(obj3.isNum()))
         cs->mat[i] = obj3.getNum();
-      obj3.free();
     }
   }
-  obj2.free();
-  obj1.free();
 
   cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
 		xyzrgb[0][1] * cs->whiteY +
@@ -1596,58 +1550,43 @@ GfxColorSpace *GfxLabColorSpace::copy() {
 
 GfxColorSpace *GfxLabColorSpace::parse(Array *arr, GfxState *state) {
   GfxLabColorSpace *cs;
-  Object obj1, obj2, obj3;
+  Object obj1, obj2;
 
-  arr->get(1, &obj1);
+  obj1 = arr->get(1);
   if (!obj1.isDict()) {
     error(errSyntaxWarning, -1, "Bad Lab color space");
-    obj1.free();
     return NULL;
   }
   cs = new GfxLabColorSpace();
-  if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 3) {
-    obj2.arrayGet(0, &obj3);
+  obj2 = obj1.dictLookup("WhitePoint");
+  if (obj2.isArray() && obj2.arrayGetLength() == 3) {
+    Object obj3 = obj2.arrayGet(0);
     cs->whiteX = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(1, &obj3);
+    obj3 = obj2.arrayGet(1);
     cs->whiteY = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(2, &obj3);
+    obj3 = obj2.arrayGet(2);
     cs->whiteZ = obj3.getNum();
-    obj3.free();
   }
-  obj2.free();
-  if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 3) {
-    obj2.arrayGet(0, &obj3);
+  obj2 = obj1.dictLookup("BlackPoint");
+  if (obj2.isArray() && obj2.arrayGetLength() == 3) {
+    Object obj3 = obj2.arrayGet(0);
     cs->blackX = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(1, &obj3);
+    obj3 = obj2.arrayGet(1);
     cs->blackY = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(2, &obj3);
+    obj3 = obj2.arrayGet(2);
     cs->blackZ = obj3.getNum();
-    obj3.free();
   }
-  obj2.free();
-  if (obj1.dictLookup("Range", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 4) {
-    obj2.arrayGet(0, &obj3);
+  obj2 = obj1.dictLookup("Range");
+  if (obj2.isArray() && obj2.arrayGetLength() == 4) {
+    Object obj3 = obj2.arrayGet(0);
     cs->aMin = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(1, &obj3);
+    obj3 = obj2.arrayGet(1);
     cs->aMax = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(2, &obj3);
+    obj3 = obj2.arrayGet(2);
     cs->bMin = obj3.getNum();
-    obj3.free();
-    obj2.arrayGet(3, &obj3);
+    obj3 = obj2.arrayGet(3);
     cs->bMax = obj3.getNum();
-    obj3.free();
   }
-  obj2.free();
-  obj1.free();
 
   cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
 		xyzrgb[0][1] * cs->whiteY +
@@ -1936,14 +1875,13 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState
     error(errSyntaxError, -1, "Bad ICCBased color space");
     return NULL;
   }
-  arr->getNF(1, &obj1);
+  obj1 = arr->getNF(1);
   if (obj1.isRef()) {
     iccProfileStreamA = obj1.getRef();
   } else {
     iccProfileStreamA.num = 0;
     iccProfileStreamA.gen = 0;
   }
-  obj1.free();
 #ifdef USE_CMS
   // check cache
   if (out && iccProfileStreamA.num > 0) {
@@ -1973,28 +1911,26 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState
     }
   }
 #endif
-  arr->get(1, &obj1);
+  obj1 = arr->get(1);
   if (!obj1.isStream()) {
     error(errSyntaxWarning, -1, "Bad ICCBased color space (stream)");
-    obj1.free();
     return NULL;
   }
   dict = obj1.streamGetDict();
-  if (!dict->lookup("N", &obj2)->isInt()) {
+  obj2 = dict->lookup("N");
+  if (!obj2.isInt()) {
     error(errSyntaxWarning, -1, "Bad ICCBased color space (N)");
-    obj2.free();
-    obj1.free();
-    return NULL;
+    return nullptr;
   }
   nCompsA = obj2.getInt();
-  obj2.free();
   if (nCompsA > 4) {
     error(errSyntaxError, -1,
 	  "ICCBased color space with too many ({0:d} > 4) components",
 	  nCompsA);
     nCompsA = 4;
   }
-  if (dict->lookup("Alternate", &obj2)->isNull() ||
+  obj2 = dict->lookup("Alternate");
+  if (obj2.isNull() ||
       !(altA = GfxColorSpace::parse(NULL, &obj2, out, state, recursion + 1))) {
     switch (nCompsA) {
     case 1:
@@ -2008,38 +1944,30 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState
       break;
     default:
       error(errSyntaxWarning, -1, "Bad ICCBased color space - invalid N");
-      obj2.free();
-      obj1.free();
       return NULL;
     }
   }
-  obj2.free();
   if (altA->getNComps() != nCompsA) {
       error(errSyntaxWarning, -1, "Bad ICCBased color space - N doesn't match alt color space");
       delete altA;
-      obj1.free();
       return NULL;
   }
   cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
-  if (dict->lookup("Range", &obj2)->isArray() &&
-      obj2.arrayGetLength() == 2 * nCompsA) {
+  obj2 = dict->lookup("Range");
+  if (obj2.isArray() && obj2.arrayGetLength() == 2 * nCompsA) {
     Object obj4;
     for (i = 0; i < nCompsA; ++i) {
-      obj2.arrayGet(2*i, &obj3);
-      obj2.arrayGet(2*i+1, &obj4);
+      obj3 = obj2.arrayGet(2*i);
+      obj4 = obj2.arrayGet(2*i+1);
       if (obj3.isNum() && obj4.isNum()) {
         cs->rangeMin[i] = obj3.getNum();
         cs->rangeMax[i] = obj4.getNum();
       }
-      obj3.free();
-      obj4.free();
     }
   }
-  obj2.free();
-  obj1.free();
 
 #ifdef USE_CMS
-  arr->get(1, &obj1);
+  obj1 = arr->get(1);
   Guchar *profBuf;
   Stream *iccStream = obj1.getStream();
   int length = 0;
@@ -2099,7 +2027,6 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState
     }
     cmsCloseProfile(hp);
   }
-  obj1.free();
   // put this colorSpace into cache
   if (out && iccProfileStreamA.num > 0) {
     GfxICCBasedColorSpaceKey *k = new GfxICCBasedColorSpaceKey(iccProfileStreamA.num, iccProfileStreamA.gen);
@@ -2581,27 +2508,26 @@ GfxColorSpace *GfxIndexedColorSpace::copy() {
 }
 
 GfxColorSpace *GfxIndexedColorSpace::parse(GfxResources *res, Array *arr, OutputDev *out, GfxState *state, int recursion) {
-  GfxIndexedColorSpace *cs;
   GfxColorSpace *baseA;
   int indexHighA;
   Object obj1;
   char *s;
-  int n, i, j;
+  int i, j;
 
   if (arr->getLength() != 4) {
     error(errSyntaxWarning, -1, "Bad Indexed color space");
-    goto err1;
+    return nullptr;
   }
-  arr->get(1, &obj1);
+  obj1 = arr->get(1);
   if (!(baseA = GfxColorSpace::parse(res, &obj1, out, state, recursion + 1))) {
     error(errSyntaxWarning, -1, "Bad Indexed color space (base color space)");
-    goto err2;
+    return nullptr;
   }
-  obj1.free();
-  if (!arr->get(2, &obj1)->isInt()) {
+  obj1 = arr->get(2);
+  if (!obj1.isInt()) {
     error(errSyntaxWarning, -1, "Bad Indexed color space (hival)");
     delete baseA;
-    goto err2;
+    return nullptr;
   }
   indexHighA = obj1.getInt();
   if (indexHighA < 0 || indexHighA > 255) {
@@ -2614,10 +2540,9 @@ GfxColorSpace *GfxIndexedColorSpace::parse(GfxResources *res, Array *arr, Output
     else indexHighA = 255;
     error(errSyntaxWarning, -1, "Bad Indexed color space (invalid indexHigh value, was {0:d} using {1:d} to try to recover)", previousValue, indexHighA);
   }
-  obj1.free();
-  cs = new GfxIndexedColorSpace(baseA, indexHighA);
-  arr->get(3, &obj1);
-  n = baseA->getNComps();
+  GfxIndexedColorSpace *cs = new GfxIndexedColorSpace(baseA, indexHighA);
+  obj1 = arr->get(3);
+  const int n = baseA->getNComps();
   if (obj1.isStream()) {
     obj1.streamReset();
     for (i = 0; i <= indexHighA; ++i) {
@@ -2643,15 +2568,11 @@ GfxColorSpace *GfxIndexedColorSpace::parse(GfxResources *res, Array *arr, Output
     error(errSyntaxWarning, -1, "Bad Indexed color space (lookup table)");
     goto err3;
   }
-  obj1.free();
   return cs;
 
  err3:
   delete cs;
- err2:
-  obj1.free();
- err1:
-  return NULL;
+  return nullptr;
 }
 
 GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
@@ -2856,19 +2777,18 @@ GfxColorSpace *GfxSeparationColorSpace::parse(GfxResources *res, Array *arr, Out
     error(errSyntaxWarning, -1, "Bad Separation color space");
     goto err1;
   }
-  if (!arr->get(1, &obj1)->isName()) {
+  obj1 = arr->get(1);
+  if (!obj1.isName()) {
     error(errSyntaxWarning, -1, "Bad Separation color space (name)");
-    goto err2;
+    goto err1;
   }
   nameA = new GooString(obj1.getName());
-  obj1.free();
-  arr->get(2, &obj1);
+  obj1 = arr->get(2);
   if (!(altA = GfxColorSpace::parse(res, &obj1, out, state, recursion + 1))) {
     error(errSyntaxWarning, -1, "Bad Separation color space (alternate color space)");
     goto err3;
   }
-  obj1.free();
-  arr->get(3, &obj1);
+  obj1 = arr->get(3);
   if (!(funcA = Function::parse(&obj1))) {
     goto err4;
   }
@@ -2876,7 +2796,6 @@ GfxColorSpace *GfxSeparationColorSpace::parse(GfxResources *res, Array *arr, Out
     error(errSyntaxWarning, -1, "Bad SeparationColorSpace function");
     goto err5;
   }
-  obj1.free();
   cs = new GfxSeparationColorSpace(nameA, altA, funcA);
   return cs;
 
@@ -2886,10 +2805,8 @@ GfxColorSpace *GfxSeparationColorSpace::parse(GfxResources *res, Array *arr, Out
   delete altA;
  err3:
   delete nameA;
- err2:
-  obj1.free();
  err1:
-  return NULL;
+  return nullptr;
 }
 
 void GfxSeparationColorSpace::getGray(GfxColor *color, GfxGray *gray) {
@@ -3136,7 +3053,7 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(GfxResources *res, Array *arr, Output
   GooString *namesA[gfxColorMaxComps];
   GfxColorSpace *altA;
   Function *funcA;
-  Object obj1, obj2;
+  Object obj1;
   int i;
   GooList *separationList = new GooList();
 
@@ -3144,9 +3061,10 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(GfxResources *res, Array *arr, Output
     error(errSyntaxWarning, -1, "Bad DeviceN color space");
     goto err1;
   }
-  if (!arr->get(1, &obj1)->isArray()) {
+  obj1 = arr->get(1);
+  if (!obj1.isArray()) {
     error(errSyntaxWarning, -1, "Bad DeviceN color space (names)");
-    goto err2;
+    goto err1;
   }
   nCompsA = obj1.arrayGetLength();
   if (nCompsA > gfxColorMaxComps) {
@@ -3155,51 +3073,42 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(GfxResources *res, Array *arr, Output
     nCompsA = gfxColorMaxComps;
   }
   for (i = 0; i < nCompsA; ++i) {
-    if (!obj1.arrayGet(i, &obj2)->isName()) {
+    Object obj2 = obj1.arrayGet(i);
+    if (!obj2.isName()) {
       error(errSyntaxWarning, -1, "Bad DeviceN color space (names)");
-      obj2.free();
-      goto err2;
+      goto err1;
     }
     namesA[i] = new GooString(obj2.getName());
-    obj2.free();
   }
-  obj1.free();
-  arr->get(2, &obj1);
+  obj1 = arr->get(2);
   if (!(altA = GfxColorSpace::parse(res, &obj1, out, state, recursion + 1))) {
     error(errSyntaxWarning, -1, "Bad DeviceN color space (alternate color space)");
     goto err3;
   }
-  obj1.free();
-  arr->get(3, &obj1);
+  obj1 = arr->get(3);
   if (!(funcA = Function::parse(&obj1))) {
     goto err4;
   }
-  obj1.free();
   if (arr->getLength() == 5) {
-    if (!arr->get(4, &obj1)->isDict()) {
+    obj1 = arr->get(4);
+    if (!obj1.isDict()) {
       error(errSyntaxWarning, -1, "Bad DeviceN color space (attributes)");
       goto err4;
     }
     Dict *attribs = obj1.getDict();
-    attribs->lookup("Colorants", &obj2);
+    Object obj2 = attribs->lookup("Colorants");
     if (obj2.isDict()) {
       Dict *colorants = obj2.getDict();
       for (i = 0; i < colorants->getLength(); i++) {
-        Object obj3;
-        colorants->getVal(i, &obj3);
+        Object obj3 = colorants->getVal(i);
         if (obj3.isArray()) {
           separationList->append(GfxSeparationColorSpace::parse(res, obj3.getArray(), out, state, recursion));
         } else {
-          obj3.free();
-          obj2.free();
           error(errSyntaxWarning, -1, "Bad DeviceN color space (colorant value entry is not an Array)");
           goto err4;
         }
-        obj3.free();
       }
     }
-    obj2.free();
-    obj1.free();
   }
   cs = new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA, separationList);
   return cs;
@@ -3210,8 +3119,6 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(GfxResources *res, Array *arr, Output
   for (i = 0; i < nCompsA; ++i) {
     delete namesA[i];
   }
- err2:
-  obj1.free();
  err1:
   delete separationList;
   return NULL;
@@ -3407,13 +3314,11 @@ GfxColorSpace *GfxPatternColorSpace::parse(GfxResources *res, Array *arr, Output
   }
   underA = NULL;
   if (arr->getLength() == 2) {
-    arr->get(1, &obj1);
+    obj1 = arr->get(1);
     if (!(underA = GfxColorSpace::parse(res, &obj1, out, state, recursion + 1))) {
       error(errSyntaxWarning, -1, "Bad Pattern color space (underlying color space)");
-      obj1.free();
       return NULL;
     }
-    obj1.free();
   }
   cs = new GfxPatternColorSpace(underA);
   return cs;
@@ -3458,11 +3363,11 @@ GfxPattern *GfxPattern::parse(GfxResources *res, Object *obj, OutputDev *out, Gf
   Object obj1;
 
   if (obj->isDict()) {
-    obj->dictLookup("PatternType", &obj1);
+    obj1 = obj->dictLookup("PatternType");
   } else if (obj->isStream()) {
-    obj->streamGetDict()->lookup("PatternType", &obj1);
+    obj1 = obj->streamGetDict()->lookup("PatternType");
   } else {
-    return NULL;
+    return nullptr;
   }
   pattern = NULL;
   if (obj1.isInt() && obj1.getInt() == 1) {
@@ -3470,7 +3375,6 @@ GfxPattern *GfxPattern::parse(GfxResources *res, Object *obj, OutputDev *out, Gf
   } else if (obj1.isInt() && obj1.getInt() == 2) {
     pattern = GfxShadingPattern::parse(res, obj, out, state);
   }
-  obj1.free();
   return pattern;
 }
 
@@ -3479,13 +3383,12 @@ GfxPattern *GfxPattern::parse(GfxResources *res, Object *obj, OutputDev *out, Gf
 //------------------------------------------------------------------------
 
 GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) {
-  GfxTilingPattern *pat;
   Dict *dict;
   int paintTypeA, tilingTypeA;
   double bboxA[4], matrixA[6];
   double xStepA, yStepA;
   Object resDictA;
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
   if (!patObj->isStream()) {
@@ -3493,71 +3396,66 @@ GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) {
   }
   dict = patObj->streamGetDict();
 
-  if (dict->lookup("PaintType", &obj1)->isInt()) {
+  obj1 = dict->lookup("PaintType");
+  if (obj1.isInt()) {
     paintTypeA = obj1.getInt();
   } else {
     paintTypeA = 1;
     error(errSyntaxWarning, -1, "Invalid or missing PaintType in pattern");
   }
-  obj1.free();
-  if (dict->lookup("TilingType", &obj1)->isInt()) {
+  obj1 = dict->lookup("TilingType");
+  if (obj1.isInt()) {
     tilingTypeA = obj1.getInt();
   } else {
     tilingTypeA = 1;
     error(errSyntaxWarning, -1, "Invalid or missing TilingType in pattern");
   }
-  obj1.free();
   bboxA[0] = bboxA[1] = 0;
   bboxA[2] = bboxA[3] = 1;
-  if (dict->lookup("BBox", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 4) {
+  obj1 = dict->lookup("BBox");
+  if (obj1.isArray() && obj1.arrayGetLength() == 4) {
     for (i = 0; i < 4; ++i) {
-      if (obj1.arrayGet(i, &obj2)->isNum()) {
+      Object obj2 = obj1.arrayGet(i);
+      if (obj2.isNum()) {
 	bboxA[i] = obj2.getNum();
       }
-      obj2.free();
     }
   } else {
     error(errSyntaxWarning, -1, "Invalid or missing BBox in pattern");
   }
-  obj1.free();
-  if (dict->lookup("XStep", &obj1)->isNum()) {
+  obj1 = dict->lookup("XStep");
+  if (obj1.isNum()) {
     xStepA = obj1.getNum();
   } else {
     xStepA = 1;
     error(errSyntaxWarning, -1, "Invalid or missing XStep in pattern");
   }
-  obj1.free();
-  if (dict->lookup("YStep", &obj1)->isNum()) {
+  obj1 = dict->lookup("YStep");
+  if (obj1.isNum()) {
     yStepA = obj1.getNum();
   } else {
     yStepA = 1;
     error(errSyntaxWarning, -1, "Invalid or missing YStep in pattern");
   }
-  obj1.free();
-  if (!dict->lookup("Resources", &resDictA)->isDict()) {
-    resDictA.free();
-    resDictA.initNull();
+  resDictA = dict->lookup("Resources");
+  if (!resDictA.isDict()) {
     error(errSyntaxWarning, -1, "Invalid or missing Resources in pattern");
   }
   matrixA[0] = 1; matrixA[1] = 0;
   matrixA[2] = 0; matrixA[3] = 1;
   matrixA[4] = 0; matrixA[5] = 0;
-  if (dict->lookup("Matrix", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 6) {
+  obj1 = dict->lookup("Matrix");
+  if (obj1.isArray() && obj1.arrayGetLength() == 6) {
     for (i = 0; i < 6; ++i) {
-      if (obj1.arrayGet(i, &obj2)->isNum()) {
+      Object obj2 = obj1.arrayGet(i);
+      if (obj2.isNum()) {
 	matrixA[i] = obj2.getNum();
       }
-      obj2.free();
     }
   }
-  obj1.free();
 
-  pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
+  return new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
 			     &resDictA, matrixA, patObj);
-  resDictA.free();
-  return pat;
 }
 
 GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
@@ -3575,16 +3473,14 @@ GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
   }
   xStep = xStepA;
   yStep = yStepA;
-  resDictA->copy(&resDict);
+  resDict = resDictA->copy();
   for (i = 0; i < 6; ++i) {
     matrix[i] = matrixA[i];
   }
-  contentStreamA->copy(&contentStream);
+  contentStream = contentStreamA->copy();
 }
 
 GfxTilingPattern::~GfxTilingPattern() {
-  resDict.free();
-  contentStream.free();
 }
 
 GfxPattern *GfxTilingPattern::copy() {
@@ -3600,7 +3496,7 @@ GfxShadingPattern *GfxShadingPattern::parse(GfxResources *res, Object *patObj, O
   Dict *dict;
   GfxShading *shadingA;
   double matrixA[6];
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
   if (!patObj->isDict()) {
@@ -3608,9 +3504,8 @@ GfxShadingPattern *GfxShadingPattern::parse(GfxResources *res, Object *patObj, O
   }
   dict = patObj->getDict();
 
-  dict->lookup("Shading", &obj1);
+  obj1 = dict->lookup("Shading");
   shadingA = GfxShading::parse(res, &obj1, out, state);
-  obj1.free();
   if (!shadingA) {
     return NULL;
   }
@@ -3618,16 +3513,15 @@ GfxShadingPattern *GfxShadingPattern::parse(GfxResources *res, Object *patObj, O
   matrixA[0] = 1; matrixA[1] = 0;
   matrixA[2] = 0; matrixA[3] = 1;
   matrixA[4] = 0; matrixA[5] = 0;
-  if (dict->lookup("Matrix", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 6) {
+  obj1 = dict->lookup("Matrix");
+  if (obj1.isArray() && obj1.arrayGetLength() == 6) {
     for (i = 0; i < 6; ++i) {
-      if (obj1.arrayGet(i, &obj2)->isNum()) {
+      Object obj2 = obj1.arrayGet(i);
+      if (obj2.isNum()) {
 	matrixA[i] = obj2.getNum();
       }
-      obj2.free();
     }
   }
-  obj1.free();
 
   return new GfxShadingPattern(shadingA, matrixA);
 }
@@ -3696,13 +3590,12 @@ GfxShading *GfxShading::parse(GfxResources *res, Object *obj, OutputDev *out, Gf
     return NULL;
   }
 
-  if (!dict->lookup("ShadingType", &obj1)->isInt()) {
+  obj1 = dict->lookup("ShadingType");
+  if (!obj1.isInt()) {
     error(errSyntaxWarning, -1, "Invalid ShadingType in shading dictionary");
-    obj1.free();
     return NULL;
   }
   typeA = obj1.getInt();
-  obj1.free();
 
   switch (typeA) {
   case 1:
@@ -3758,43 +3651,41 @@ GfxShading *GfxShading::parse(GfxResources *res, Object *obj, OutputDev *out, Gf
 }
 
 GBool GfxShading::init(GfxResources *res, Dict *dict, OutputDev *out, GfxState *state) {
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
-  dict->lookup("ColorSpace", &obj1);
+  obj1 = dict->lookup("ColorSpace");
   if (!(colorSpace = GfxColorSpace::parse(res, &obj1, out, state))) {
     error(errSyntaxWarning, -1, "Bad color space in shading dictionary");
-    obj1.free();
     return gFalse;
   }
-  obj1.free();
 
   for (i = 0; i < gfxColorMaxComps; ++i) {
     background.c[i] = 0;
   }
   hasBackground = gFalse;
-  if (dict->lookup("Background", &obj1)->isArray()) {
+  obj1 = dict->lookup("Background");
+  if (obj1.isArray()) {
     if (obj1.arrayGetLength() == colorSpace->getNComps()) {
       hasBackground = gTrue;
       for (i = 0; i < colorSpace->getNComps(); ++i) {
-	background.c[i] = dblToCol(obj1.arrayGet(i, &obj2)->getNum());
-	obj2.free();
+	Object obj2 = obj1.arrayGet(i);
+	background.c[i] = dblToCol(obj2.getNum());
       }
     } else {
       error(errSyntaxWarning, -1, "Bad Background in shading dictionary");
     }
   }
-  obj1.free();
 
   xMin = yMin = xMax = yMax = 0;
   hasBBox = gFalse;
-  if (dict->lookup("BBox", &obj1)->isArray()) {
+  obj1 = dict->lookup("BBox");
+  if (obj1.isArray()) {
     if (obj1.arrayGetLength() == 4) {
-      Object obj3, obj4, obj5;
-      obj1.arrayGet(0, &obj2);
-      obj1.arrayGet(1, &obj3);
-      obj1.arrayGet(2, &obj4);
-      obj1.arrayGet(3, &obj5);
+      Object obj2 = obj1.arrayGet(0);
+      Object obj3 = obj1.arrayGet(1);
+      Object obj4 = obj1.arrayGet(2);
+      Object obj5 = obj1.arrayGet(3);
       if (obj2.isNum() && obj3.isNum() && obj4.isNum() && obj5.isNum())
       {
         hasBBox = gTrue;
@@ -3805,15 +3696,10 @@ GBool GfxShading::init(GfxResources *res, Dict *dict, OutputDev *out, GfxState *
       } else {
         error(errSyntaxWarning, -1, "Bad BBox in shading dictionary (Values not numbers)");
       }
-      obj2.free();
-      obj3.free();
-      obj4.free();
-      obj5.free();
     } else {
       error(errSyntaxWarning, -1, "Bad BBox in shading dictionary");
     }
   }
-  obj1.free();
 
   return gTrue;
 }
@@ -3875,65 +3761,53 @@ GfxFunctionShading *GfxFunctionShading::parse(GfxResources *res, Dict *dict, Out
   double matrixA[6];
   Function *funcsA[gfxColorMaxComps];
   int nFuncsA;
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
   x0A = y0A = 0;
   x1A = y1A = 1;
-  if (dict->lookup("Domain", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 4) {
-    x0A = obj1.arrayGet(0, &obj2)->getNum();
-    obj2.free();
-    x1A = obj1.arrayGet(1, &obj2)->getNum();
-    obj2.free();
-    y0A = obj1.arrayGet(2, &obj2)->getNum();
-    obj2.free();
-    y1A = obj1.arrayGet(3, &obj2)->getNum();
-    obj2.free();
-  }
-  obj1.free();
+  obj1 = dict->lookup("Domain");
+  if (obj1.isArray() && obj1.arrayGetLength() == 4) {
+    Object obj2;
+    x0A = (obj2 = obj1.arrayGet(0), obj2.getNum());
+    x1A = (obj2 = obj1.arrayGet(1), obj2.getNum());
+    y0A = (obj2 = obj1.arrayGet(2), obj2.getNum());
+    y1A = (obj2 = obj1.arrayGet(3), obj2.getNum());
+  }
 
   matrixA[0] = 1; matrixA[1] = 0;
   matrixA[2] = 0; matrixA[3] = 1;
   matrixA[4] = 0; matrixA[5] = 0;
-  if (dict->lookup("Matrix", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 6) {
-    matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
-    obj2.free();
-    matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
-    obj2.free();
-    matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
-    obj2.free();
-    matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
-    obj2.free();
-    matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
-    obj2.free();
-    matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
-    obj2.free();
-  }
-  obj1.free();
-
-  dict->lookup("Function", &obj1);
+  obj1 = dict->lookup("Matrix");
+  if (obj1.isArray() && obj1.arrayGetLength() == 6) {
+    Object obj2;
+    matrixA[0] = (obj2 = obj1.arrayGet(0), obj2.getNum());
+    matrixA[1] = (obj2 = obj1.arrayGet(1), obj2.getNum());
+    matrixA[2] = (obj2 = obj1.arrayGet(2), obj2.getNum());
+    matrixA[3] = (obj2 = obj1.arrayGet(3), obj2.getNum());
+    matrixA[4] = (obj2 = obj1.arrayGet(4), obj2.getNum());
+    matrixA[5] = (obj2 = obj1.arrayGet(5), obj2.getNum());
+  }
+
+  obj1 = dict->lookup("Function");
   if (obj1.isArray()) {
     nFuncsA = obj1.arrayGetLength();
     if (nFuncsA > gfxColorMaxComps || nFuncsA <= 0) {
       error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary");
-      goto err1;
+      return nullptr;
     }
     for (i = 0; i < nFuncsA; ++i) {
-      obj1.arrayGet(i, &obj2);
+      Object obj2 = obj1.arrayGet(i);
       if (!(funcsA[i] = Function::parse(&obj2))) {
-	goto err2;
+	return nullptr;
       }
-      obj2.free();
     }
   } else {
     nFuncsA = 1;
     if (!(funcsA[0] = Function::parse(&obj1))) {
-      goto err1;
+      return nullptr;
     }
   }
-  obj1.free();
 
   shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
 				   funcsA, nFuncsA);
@@ -3942,12 +3816,6 @@ GfxFunctionShading *GfxFunctionShading::parse(GfxResources *res, Dict *dict, Out
     return NULL;
   }
   return shading;
-
- err2:
-  obj2.free();
- err1:
-  obj1.free();
-  return NULL;
 }
 
 GfxShading *GfxFunctionShading::copy() {
@@ -4195,104 +4063,83 @@ GfxAxialShading *GfxAxialShading::parse(GfxResources *res, Dict *dict, OutputDev
   Function *funcsA[gfxColorMaxComps];
   int nFuncsA;
   GBool extend0A, extend1A;
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
   x0A = y0A = x1A = y1A = 0;
-  if (dict->lookup("Coords", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 4) {
-    Object obj3, obj4, obj5;
-    obj1.arrayGet(0, &obj2);
-    obj1.arrayGet(1, &obj3);
-    obj1.arrayGet(2, &obj4);
-    obj1.arrayGet(3, &obj5);
+  obj1 = dict->lookup("Coords");
+  if (obj1.isArray() && obj1.arrayGetLength() == 4) {
+    Object obj2 = obj1.arrayGet(0);
+    Object obj3 = obj1.arrayGet(1);
+    Object obj4 = obj1.arrayGet(2);
+    Object obj5 = obj1.arrayGet(3);
     if (obj2.isNum() && obj3.isNum() && obj4.isNum() && obj5.isNum()) {
       x0A = obj2.getNum();
       y0A = obj3.getNum();
       x1A = obj4.getNum();
       y1A = obj5.getNum();
     }
-    obj2.free();
-    obj3.free();
-    obj4.free();
-    obj5.free();
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid Coords in shading dictionary");
-    goto err1;
+    return nullptr;
   }
-  obj1.free();
 
   t0A = 0;
   t1A = 1;
-  if (dict->lookup("Domain", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 2) {
-    Object obj3;
-    obj1.arrayGet(0, &obj2);
-    obj1.arrayGet(1, &obj3);
+  obj1 = dict->lookup("Domain");
+  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+    Object obj2 = obj1.arrayGet(0);
+    Object obj3 = obj1.arrayGet(1);
     if (obj2.isNum() && obj3.isNum()) {
       t0A = obj2.getNum();
       t1A = obj3.getNum();
     }
-    obj2.free();
-    obj3.free();
   }
-  obj1.free();
 
-  dict->lookup("Function", &obj1);
+  obj1 = dict->lookup("Function");
   if (obj1.isArray()) {
     nFuncsA = obj1.arrayGetLength();
     if (nFuncsA > gfxColorMaxComps || nFuncsA == 0) {
       error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary");
-      goto err1;
+      return nullptr;
     }
     for (i = 0; i < nFuncsA; ++i) {
-      obj1.arrayGet(i, &obj2);
+      Object obj2 = obj1.arrayGet(i);
       if (!(funcsA[i] = Function::parse(&obj2))) {
-	obj1.free();
-	obj2.free();
-	goto err1;
+	return nullptr;
       }
-      obj2.free();
     }
   } else {
     nFuncsA = 1;
     if (!(funcsA[0] = Function::parse(&obj1))) {
-      obj1.free();
-      goto err1;
+      return nullptr;
     }
   }
-  obj1.free();
 
   extend0A = extend1A = gFalse;
-  if (dict->lookup("Extend", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 2) {
-    obj1.arrayGet(0, &obj2);
+  obj1 = dict->lookup("Extend");
+  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+    Object obj2 = obj1.arrayGet(0);
     if (obj2.isBool()) {
       extend0A = obj2.getBool();
     } else {
       error(errSyntaxWarning, -1, "Invalid axial shading extend (0)");
     }
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     if (obj2.isBool()) {
       extend1A = obj2.getBool();
     } else {
       error(errSyntaxWarning, -1, "Invalid axial shading extend (1)");
     }
-    obj2.free();
   }
-  obj1.free();
 
   shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
 				funcsA, nFuncsA, extend0A, extend1A);
   if (!shading->init(res, dict, out, state)) {
     delete shading;
-    return NULL;
+    shading = nullptr;
   }
   return shading;
-
- err1:
-  return NULL;
 }
 
 GfxShading *GfxAxialShading::copy() {
@@ -4403,75 +4250,60 @@ GfxRadialShading *GfxRadialShading::parse(GfxResources *res, Dict *dict, OutputD
   Function *funcsA[gfxColorMaxComps];
   int nFuncsA;
   GBool extend0A, extend1A;
-  Object obj1, obj2;
+  Object obj1;
   int i;
 
   x0A = y0A = r0A = x1A = y1A = r1A = 0;
-  if (dict->lookup("Coords", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 6) {
-    x0A = obj1.arrayGet(0, &obj2)->getNum();
-    obj2.free();
-    y0A = obj1.arrayGet(1, &obj2)->getNum();
-    obj2.free();
-    r0A = obj1.arrayGet(2, &obj2)->getNum();
-    obj2.free();
-    x1A = obj1.arrayGet(3, &obj2)->getNum();
-    obj2.free();
-    y1A = obj1.arrayGet(4, &obj2)->getNum();
-    obj2.free();
-    r1A = obj1.arrayGet(5, &obj2)->getNum();
-    obj2.free();
+  obj1 = dict->lookup("Coords");
+  if (obj1.isArray() && obj1.arrayGetLength() == 6) {
+    Object obj2;
+    x0A = (obj2 = obj1.arrayGet(0), obj2.getNum());
+    y0A = (obj2 = obj1.arrayGet(1), obj2.getNum());
+    r0A = (obj2 = obj1.arrayGet(2), obj2.getNum());
+    x1A = (obj2 = obj1.arrayGet(3), obj2.getNum());
+    y1A = (obj2 = obj1.arrayGet(4), obj2.getNum());
+    r1A = (obj2 = obj1.arrayGet(5), obj2.getNum());
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid Coords in shading dictionary");
-    goto err1;
+    return nullptr;
   }
-  obj1.free();
 
   t0A = 0;
   t1A = 1;
-  if (dict->lookup("Domain", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 2) {
-    t0A = obj1.arrayGet(0, &obj2)->getNum();
-    obj2.free();
-    t1A = obj1.arrayGet(1, &obj2)->getNum();
-    obj2.free();
+  obj1 = dict->lookup("Domain");
+  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+    Object obj2;
+    t0A = (obj2 = obj1.arrayGet(0), obj2.getNum());
+    t1A = (obj2 = obj1.arrayGet(1), obj2.getNum());
   }
-  obj1.free();
 
-  dict->lookup("Function", &obj1);
+  obj1 = dict->lookup("Function");
   if (obj1.isArray()) {
     nFuncsA = obj1.arrayGetLength();
     if (nFuncsA > gfxColorMaxComps) {
       error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary");
-      goto err1;
+      return nullptr;
     }
     for (i = 0; i < nFuncsA; ++i) {
-      obj1.arrayGet(i, &obj2);
+      Object obj2 = obj1.arrayGet(i);
       if (!(funcsA[i] = Function::parse(&obj2))) {
-	obj1.free();
-	obj2.free();
-	goto err1;
+	return nullptr;
       }
-      obj2.free();
     }
   } else {
     nFuncsA = 1;
     if (!(funcsA[0] = Function::parse(&obj1))) {
-      obj1.free();
-      goto err1;
+      return nullptr;
     }
   }
-  obj1.free();
 
   extend0A = extend1A = gFalse;
-  if (dict->lookup("Extend", &obj1)->isArray() &&
-      obj1.arrayGetLength() == 2) {
-    extend0A = obj1.arrayGet(0, &obj2)->getBool();
-    obj2.free();
-    extend1A = obj1.arrayGet(1, &obj2)->getBool();
-    obj2.free();
+  obj1 = dict->lookup("Extend");
+  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+    Object obj2;
+    extend0A = (obj2 = obj1.arrayGet(0), obj2.getBool());
+    extend1A = (obj2 = obj1.arrayGet(1), obj2.getBool());
   }
-  obj1.free();
 
   shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
 				 funcsA, nFuncsA, extend0A, extend1A);
@@ -4480,9 +4312,6 @@ GfxRadialShading *GfxRadialShading::parse(GfxResources *res, Dict *dict, OutputD
     return NULL;
   }
   return shading;
-
- err1:
-  return NULL;
 }
 
 GfxShading *GfxRadialShading::copy() {
@@ -4934,94 +4763,84 @@ GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(GfxResources *res, i
   Guint x, y, flag;
   Guint c[gfxColorMaxComps];
   GfxShadingBitBuf *bitBuf;
-  Object obj1, obj2;
+  Object obj1;
   int i, j, k, state;
 
-  if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
+  obj1 = dict->lookup("BitsPerCoordinate");
+  if (obj1.isInt()) {
     coordBits = obj1.getInt();
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid BitsPerCoordinate in shading dictionary");
-    goto err2;
+    return nullptr;
   }
-  obj1.free();
-  if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
+  obj1 = dict->lookup("BitsPerComponent");
+  if (obj1.isInt()) {
     compBits = obj1.getInt();
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid BitsPerComponent in shading dictionary");
-    goto err2;
+    return nullptr;
   }
-  obj1.free();
   flagBits = vertsPerRow = 0; // make gcc happy
   if (typeA == 4) {
-    if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
+    obj1 = dict->lookup("BitsPerFlag");
+  if (obj1.isInt()) {
       flagBits = obj1.getInt();
     } else {
       error(errSyntaxWarning, -1, "Missing or invalid BitsPerFlag in shading dictionary");
-      goto err2;
+      return nullptr;
     }
-    obj1.free();
   } else {
-    if (dict->lookup("VerticesPerRow", &obj1)->isInt()) {
+    obj1 = dict->lookup("VerticesPerRow");
+  if (obj1.isInt()) {
       vertsPerRow = obj1.getInt();
     } else {
       error(errSyntaxWarning, -1, "Missing or invalid VerticesPerRow in shading dictionary");
-      goto err2;
+      return nullptr;
     }
-    obj1.free();
   }
-  if (dict->lookup("Decode", &obj1)->isArray() &&
-      obj1.arrayGetLength() >= 6) {
-    xMin = obj1.arrayGet(0, &obj2)->getNum();
-    obj2.free();
-    xMax = obj1.arrayGet(1, &obj2)->getNum();
-    obj2.free();
+  obj1 = dict->lookup("Decode");
+  if (obj1.isArray() && obj1.arrayGetLength() >= 6) {
+    Object obj2;
+    xMin = (obj2 = obj1.arrayGet(0), obj2.getNum());
+    xMax = (obj2 = obj1.arrayGet(1), obj2.getNum());
     xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
-    yMin = obj1.arrayGet(2, &obj2)->getNum();
-    obj2.free();
-    yMax = obj1.arrayGet(3, &obj2)->getNum();
-    obj2.free();
+    yMin = (obj2 = obj1.arrayGet(2), obj2.getNum());
+    yMax = (obj2 = obj1.arrayGet(3), obj2.getNum());
     yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
     for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
-      cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
-      obj2.free();
-      cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
-      obj2.free();
+      cMin[i] = (obj2 = obj1.arrayGet(4 + 2*i), obj2.getNum());
+      cMax[i] = (obj2 = obj1.arrayGet(5 + 2*i), obj2.getNum());
       cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
     }
     nComps = i;
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid Decode array in shading dictionary");
-    goto err2;
+    return nullptr;
   }
-  obj1.free();
 
-  if (!dict->lookup("Function", &obj1)->isNull()) {
+  obj1 = dict->lookup("Function");
+  if (!obj1.isNull()) {
     if (obj1.isArray()) {
       nFuncsA = obj1.arrayGetLength();
       if (nFuncsA > gfxColorMaxComps) {
 	error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary");
-	goto err1;
+	return nullptr;
       }
       for (i = 0; i < nFuncsA; ++i) {
-	obj1.arrayGet(i, &obj2);
+	Object obj2 = obj1.arrayGet(i);
 	if (!(funcsA[i] = Function::parse(&obj2))) {
-	  obj1.free();
-	  obj2.free();
-	  goto err1;
+	  return nullptr;
 	}
-	obj2.free();
       }
     } else {
       nFuncsA = 1;
       if (!(funcsA[0] = Function::parse(&obj1))) {
-	obj1.free();
-	goto err1;
+	return nullptr;
       }
     }
   } else {
     nFuncsA = 0;
   }
-  obj1.free();
 
   nVerticesA = nTrianglesA = 0;
   verticesA = NULL;
@@ -5120,11 +4939,6 @@ GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(GfxResources *res, i
     return NULL;
   }
   return shading;
-
- err2:
-  obj1.free();
- err1:
-  return NULL;
 }
 
 GfxShading *GfxGouraudTriangleShading::copy() {
@@ -5285,83 +5099,73 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(GfxResources *res, int typeA, Di
   double c[4][gfxColorMaxComps];
   Guint ci;
   GfxShadingBitBuf *bitBuf;
-  Object obj1, obj2;
+  Object obj1;
   int i, j;
 
-  if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
+  obj1 = dict->lookup("BitsPerCoordinate");
+  if (obj1.isInt()) {
     coordBits = obj1.getInt();
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid BitsPerCoordinate in shading dictionary");
-    goto err2;
+    return nullptr;
   }
-  obj1.free();
-  if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
+  obj1 = dict->lookup("BitsPerComponent");
+  if (obj1.isInt()) {
     compBits = obj1.getInt();
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid BitsPerComponent in shading dictionary");
-    goto err2;
+    return nullptr;
   }
-  obj1.free();
-  if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
+  obj1 = dict->lookup("BitsPerFlag");
+  if (obj1.isInt()) {
     flagBits = obj1.getInt();
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid BitsPerFlag in shading dictionary");
-    goto err2;
-  }
-  obj1.free();
-  if (dict->lookup("Decode", &obj1)->isArray() &&
-      obj1.arrayGetLength() >= 6) {
-    xMin = obj1.arrayGet(0, &obj2)->getNum();
-    obj2.free();
-    xMax = obj1.arrayGet(1, &obj2)->getNum();
-    obj2.free();
+    return nullptr;
+  }
+  obj1 = dict->lookup("Decode");
+  if (obj1.isArray() && obj1.arrayGetLength() >= 6) {
+    Object obj2;
+    xMin = (obj2 = obj1.arrayGet(0), obj2.getNum());
+    xMax = (obj2 = obj1.arrayGet(1), obj2.getNum());
     xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
-    yMin = obj1.arrayGet(2, &obj2)->getNum();
-    obj2.free();
-    yMax = obj1.arrayGet(3, &obj2)->getNum();
-    obj2.free();
+    yMin = (obj2 = obj1.arrayGet(2), obj2.getNum());
+    yMax = (obj2 = obj1.arrayGet(3), obj2.getNum());
     yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
     for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
-      cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
-      obj2.free();
-      cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
-      obj2.free();
+      cMin[i] = (obj2 = obj1.arrayGet(4 + 2*i), obj2.getNum());
+      cMax[i] = (obj2 = obj1.arrayGet(5 + 2*i), obj2.getNum());
       cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
     }
     nComps = i;
   } else {
     error(errSyntaxWarning, -1, "Missing or invalid Decode array in shading dictionary");
-    goto err2;
+    return nullptr;
   }
-  obj1.free();
 
-  if (!dict->lookup("Function", &obj1)->isNull()) {
+  obj1 = dict->lookup("Function");
+  if (!obj1.isNull()) {
     if (obj1.isArray()) {
       nFuncsA = obj1.arrayGetLength();
       if (nFuncsA > gfxColorMaxComps) {
 	error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary");
-	goto err1;
+	return nullptr;
       }
       for (i = 0; i < nFuncsA; ++i) {
-	obj1.arrayGet(i, &obj2);
+	Object obj2 = obj1.arrayGet(i);
 	if (!(funcsA[i] = Function::parse(&obj2))) {
-	  obj1.free();
-	  obj2.free();
-	  goto err1;
+	  return nullptr;
 	}
-	obj2.free();
       }
     } else {
       nFuncsA = 1;
       if (!(funcsA[0] = Function::parse(&obj1))) {
-	obj1.free();
-	goto err1;
+	return nullptr;
       }
     }
   } else {
     nFuncsA = 0;
   }
-  obj1.free();
 
   nPatchesA = 0;
   patchesA = NULL;
@@ -5462,7 +5266,7 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(GfxResources *res, int typeA, Di
 	break;
       case 1:
 	if (nPatchesA == 0) {
-	  goto err1;
+	  return nullptr;
 	}
 	p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
 	p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
@@ -5497,7 +5301,7 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(GfxResources *res, int typeA, Di
 	break;
       case 2:
 	if (nPatchesA == 0) {
-	  goto err1;
+	  return nullptr;
 	}
 	p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
 	p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
@@ -5532,7 +5336,7 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(GfxResources *res, int typeA, Di
 	break;
       case 3:
 	if (nPatchesA == 0) {
-	  goto err1;
+	  return nullptr;
 	}
 	p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
 	p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
@@ -5610,7 +5414,7 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(GfxResources *res, int typeA, Di
 	break;
       case 1:
 	if (nPatchesA == 0) {
-	  goto err1;
+	  return nullptr;
 	}
 	p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
 	p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
@@ -5653,7 +5457,7 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(GfxResources *res, int typeA, Di
 	break;
       case 2:
 	if (nPatchesA == 0) {
-	  goto err1;
+	  return nullptr;
 	}
 	p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
 	p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
@@ -5696,7 +5500,7 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(GfxResources *res, int typeA, Di
 	break;
       case 3:
 	if (nPatchesA == 0) {
-	  goto err1;
+	  return nullptr;
 	}
 	p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
 	p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
@@ -5794,14 +5598,9 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(GfxResources *res, int typeA, Di
 				    funcsA, nFuncsA);
   if (!shading->init(res, dict, out, state)) {
     delete shading;
-    return NULL;
+    return nullptr;
   }
   return shading;
-
- err2:
-  obj1.free();
- err1:
-  return NULL;
 }
 
 void GfxPatchMeshShading::getParameterizedColor(double t, GfxColor *color) {
@@ -5830,7 +5629,6 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
   int maxPixel, indexHigh;
   Guchar *indexedLookup;
   Function *sepFunc;
-  Object obj;
   double x[gfxColorMaxComps];
   double y[gfxColorMaxComps];
   int i, j, k;
@@ -5872,18 +5670,16 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
       nComps = colorSpace->getNComps();
     }
     for (i = 0; i < nComps; ++i) {
-      decode->arrayGet(2*i, &obj);
+      Object obj = decode->arrayGet(2*i);
       if (!obj.isNum()) {
-	goto err2;
+	goto err1;
       }
       decodeLow[i] = obj.getNum();
-      obj.free();
-      decode->arrayGet(2*i+1, &obj);
+      obj = decode->arrayGet(2*i+1);
       if (!obj.isNum()) {
-	goto err2;
+	goto err1;
       }
       decodeRange[i] = obj.getNum() - decodeLow[i];
-      obj.free();
     }
   } else {
     goto err1;
@@ -5988,8 +5784,6 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
 
   return;
 
- err2:
-  obj.free();
  err1:
   ok = gFalse;
 }
@@ -7313,7 +7107,6 @@ GfxState *GfxState::restore() {
 }
 
 GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) {
-  Object obj2;
   int i, j;
 
   if (obj->isName()) {
@@ -7326,19 +7119,16 @@ GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) {
     return gFalse;
   } else if (obj->isArray()) {
     for (i = 0; i < obj->arrayGetLength(); ++i) {
-      obj->arrayGet(i, &obj2);
+      Object obj2 = obj->arrayGet(i);
       if (!obj2.isName()) {
-	obj2.free();
 	return gFalse;
       }
       for (j = 0; j < nGfxBlendModeNames; ++j) {
 	if (!strcmp(obj2.getName(), gfxBlendModeNames[j].name)) {
-	  obj2.free();
 	  *mode = gfxBlendModeNames[j].mode;
 	  return gTrue;
 	}
       }
-      obj2.free();
     }
     *mode = gfxBlendNormal;
     return gTrue;
diff --git a/poppler/Hints.cc b/poppler/Hints.cc
index 7f11304e..1cadb059 100644
--- a/poppler/Hints.cc
+++ b/poppler/Hints.cc
@@ -181,42 +181,38 @@ void Hints::readTables(BaseStream *str, Linearization *linearization, XRef *xref
   hintsLength2 = linearization->getHintsLength2();
 
   Parser *parser;
-  Object obj;
 
   int bufLength = hintsLength + hintsLength2;
 
   std::vector<char> buf(bufLength);
   char *p = &buf[0];
 
-  obj.initNull();
-  Stream *s = str->makeSubStream(hintsOffset, gFalse, hintsLength, &obj);
+  Stream *s = str->makeSubStream(hintsOffset, gFalse, hintsLength, Object(objNull));
   s->reset();
   for (Guint i=0; i < hintsLength; i++) { *p++ = s->getChar(); }
   delete s;
 
   if (hintsOffset2 && hintsLength2) {
-    obj.initNull();
-    s = str->makeSubStream(hintsOffset2, gFalse, hintsLength2, &obj);
+    s = str->makeSubStream(hintsOffset2, gFalse, hintsLength2, Object(objNull));
     s->reset();
     for (Guint i=0; i < hintsLength2; i++) { *p++ = s->getChar(); }
     delete s;
   }
 
-  obj.initNull();
-  MemStream *memStream = new MemStream (&buf[0], 0, bufLength, &obj);
+  MemStream *memStream = new MemStream (&buf[0], 0, bufLength, Object(objNull));
 
-  obj.initNull();
   parser = new Parser(xref, new Lexer(xref, memStream), gTrue);
 
   int num, gen;
-  if (parser->getObj(&obj)->isInt() &&
-     (num = obj.getInt(), obj.free(), parser->getObj(&obj)->isInt()) &&
-     (gen = obj.getInt(), obj.free(), parser->getObj(&obj)->isCmd("obj")) &&
-     (obj.free(), parser->getObj(&obj, gFalse,
+  Object obj;
+  if ((obj = parser->getObj(), obj.isInt()) &&
+     (num = obj.getInt(), obj = parser->getObj(), obj.isInt()) &&
+     (gen = obj.getInt(), obj = parser->getObj(), obj.isCmd("obj")) &&
+     (obj = parser->getObj(gFalse,
          secHdlr ? secHdlr->getFileKey() : (Guchar *)NULL,
          secHdlr ? secHdlr->getEncAlgorithm() : cryptRC4,
          secHdlr ? secHdlr->getFileKeyLength() : 0,
-         num, gen, 0, gTrue)->isStream())) {
+         num, gen, 0, gTrue), obj.isStream())) {
     Stream *hintsStream = obj.getStream();
     Dict *hintsDict = obj.streamGetDict();
 
@@ -238,7 +234,6 @@ void Hints::readTables(BaseStream *str, Linearization *linearization, XRef *xref
   } else {
     error(errSyntaxWarning, -1, "Failed parsing hints table object");
   }
-  obj.free();
 
   delete parser;
 }
diff --git a/poppler/JBIG2Stream.cc b/poppler/JBIG2Stream.cc
index d26ba02b..9706d495 100644
--- a/poppler/JBIG2Stream.cc
+++ b/poppler/JBIG2Stream.cc
@@ -1197,7 +1197,7 @@ JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStreamA, Object *globalsSt
   mmrDecoder = new JBIG2MMRDecoder();
 
   if (globalsStreamA->isStream()) {
-    globalsStreamA->copy(&globalsStream);
+    globalsStream = globalsStreamA->copy();
     if (globalsStreamRefA->isRef())
       globalsStreamRef = globalsStreamRefA->getRef();
   }
@@ -1209,7 +1209,6 @@ JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStreamA, Object *globalsSt
 
 JBIG2Stream::~JBIG2Stream() {
   close();
-  globalsStream.free();
   delete arithDecoder;
   delete genericRegionStats;
   delete refinementRegionStats;
diff --git a/poppler/JPEG2000Stream.cc b/poppler/JPEG2000Stream.cc
index 7daa23d6..5b46a276 100644
--- a/poppler/JPEG2000Stream.cc
+++ b/poppler/JPEG2000Stream.cc
@@ -363,25 +363,22 @@ static OPJ_BOOL jpxSeek_callback(OPJ_OFF_T seek_pos, void * p_user_data)
 void JPXStream::init()
 {
   Object oLen, cspace, smaskInData;
-  if (getDict()) getDict()->lookup("Length", &oLen);
-  if (getDict()) getDict()->lookup("ColorSpace", &cspace);
-  if (getDict()) getDict()->lookup("SMaskInData", &smaskInData);
+  if (getDict()) {
+    oLen = getDict()->lookup("Length");
+    cspace = getDict()->lookup("ColorSpace");
+    smaskInData = getDict()->lookup("SMaskInData");
+  }
 
   int bufSize = BUFFER_INITIAL_SIZE;
   if (oLen.isInt()) bufSize = oLen.getInt();
-  oLen.free();
 
   if (cspace.isArray() && cspace.arrayGetLength() > 0) {
-    Object cstype;
-    cspace.arrayGet(0, &cstype);
+    Object cstype = cspace.arrayGet(0);
     if (cstype.isName("Indexed")) priv->indexed = gTrue;
-    cstype.free();
   }
-  cspace.free();
 
   priv->smaskInData = 0;
   if (smaskInData.isInt()) priv->smaskInData = smaskInData.getInt();
-  smaskInData.free();
 
   int length = 0;
   unsigned char *buf = str->toUnsignedChars(&length, bufSize);
diff --git a/poppler/Lexer.cc b/poppler/Lexer.cc
index 952967a9..ef15a4b1 100644
--- a/poppler/Lexer.cc
+++ b/poppler/Lexer.cc
@@ -70,36 +70,33 @@ static const long long LongLongSafeLimit = (LLONG_MAX - 9) / 10;
 //------------------------------------------------------------------------
 
 Lexer::Lexer(XRef *xrefA, Stream *str) {
-  Object obj;
-
   lookCharLastValueCached = LOOK_VALUE_NOT_CACHED;
   xref = xrefA;
 
-  curStr.initStream(str);
+  curStr = Object(str);
   streams = new Array(xref);
-  streams->add(curStr.copy(&obj));
+  streams->add(curStr.copy());
   strPtr = 0;
   freeArray = gTrue;
   curStr.streamReset();
 }
 
 Lexer::Lexer(XRef *xrefA, Object *obj) {
-  Object obj2;
-
   lookCharLastValueCached = LOOK_VALUE_NOT_CACHED;
   xref = xrefA;
 
   if (obj->isStream()) {
+    Object obj2;
     streams = new Array(xref);
     freeArray = gTrue;
-    streams->add(obj->copy(&obj2));
+    streams->add(obj->copy());
   } else {
     streams = obj->getArray();
     freeArray = gFalse;
   }
   strPtr = 0;
   if (streams->getLength() > 0) {
-    streams->get(strPtr, &curStr);
+    curStr = streams->get(strPtr);
     curStr.streamReset();
   }
 }
@@ -107,7 +104,6 @@ Lexer::Lexer(XRef *xrefA, Object *obj) {
 Lexer::~Lexer() {
   if (!curStr.isNone()) {
     curStr.streamClose();
-    curStr.free();
   }
   if (freeArray) {
     delete streams;
@@ -129,10 +125,10 @@ int Lexer::getChar(GBool comesFromLook) {
       return EOF;
     } else {
       curStr.streamClose();
-      curStr.free();
+      curStr = Object();
       ++strPtr;
       if (strPtr < streams->getLength()) {
-        streams->get(strPtr, &curStr);
+        curStr = streams->get(strPtr);
         curStr.streamReset();
       }
     }
@@ -154,7 +150,7 @@ int Lexer::lookChar() {
   }
 }
 
-Object *Lexer::getObj(Object *obj, int objNum) {
+Object Lexer::getObj(int objNum) {
   char *p;
   int c, c2;
   GBool comment, neg, done, overflownInteger, overflownLongLong;
@@ -169,7 +165,7 @@ Object *Lexer::getObj(Object *obj, int objNum) {
   comment = gFalse;
   while (1) {
     if ((c = getChar()) == EOF) {
-      return obj->initEOF();
+      return Object(objEOF);
     }
     if (comment) {
       if (c == '\r' || c == '\n')
@@ -236,16 +232,16 @@ Object *Lexer::getObj(Object *obj, int objNum) {
     }
     if (unlikely(overflownInteger)) {
       if (overflownLongLong) {
-        obj->initReal(xf);
+        return Object(xf);
       } else {
         if (unlikely(xll == INT_MIN)) {
-          obj->initInt(INT_MIN);
+          return Object(static_cast<int>(INT_MIN));
         } else {
-          obj->initInt64(xll);
+          return Object(xll);
         }
       }
     } else {
-      obj->initInt(xi);
+      return Object(xi);
     }
     break;
   doReal:
@@ -274,7 +270,7 @@ Object *Lexer::getObj(Object *obj, int objNum) {
     if (neg) {
       xf = -xf;
     }
-    obj->initReal(xf);
+    return Object(xf);
     break;
 
   // string
@@ -401,9 +397,9 @@ Object *Lexer::getObj(Object *obj, int objNum) {
         s = new GooString(tokBuf, n);
       else
         s->append(tokBuf, n);
-      obj->initString(s);
+      return Object(s);
     } else {
-      obj->initEOF();
+      return Object(objEOF);
     }
     break;
 
@@ -455,10 +451,11 @@ Object *Lexer::getObj(Object *obj, int objNum) {
     }
     if (n < tokBufSize) {
       *p = '\0';
-      obj->initName(tokBuf);
+      return Object(objName, tokBuf);
     } else {
-      obj->initName(s->getCString());
+      Object obj(objName, s->getCString());
       delete s;
+      return obj;
     }
     break;
 
@@ -467,7 +464,7 @@ Object *Lexer::getObj(Object *obj, int objNum) {
   case ']':
     tokBuf[0] = c;
     tokBuf[1] = '\0';
-    obj->initCmd(tokBuf);
+    return Object(objCmd, tokBuf);
     break;
 
   // hex string or dict punctuation
@@ -479,7 +476,7 @@ Object *Lexer::getObj(Object *obj, int objNum) {
       getChar();
       tokBuf[0] = tokBuf[1] = '<';
       tokBuf[2] = '\0';
-      obj->initCmd(tokBuf);
+      return Object(objCmd, tokBuf);
 
     // hex string
     } else {
@@ -526,7 +523,7 @@ Object *Lexer::getObj(Object *obj, int objNum) {
 	s->append(tokBuf, n);
       if (m == 1)
 	s->append((char)(c2 << 4));
-      obj->initString(s);
+      return Object(s);
     }
     break;
 
@@ -537,10 +534,10 @@ Object *Lexer::getObj(Object *obj, int objNum) {
       getChar();
       tokBuf[0] = tokBuf[1] = '>';
       tokBuf[2] = '\0';
-      obj->initCmd(tokBuf);
+      return Object(objCmd, tokBuf);
     } else {
       error(errSyntaxError, getPos(), "Illegal character '>'");
-      obj->initError();
+      return Object(objError);
     }
     break;
 
@@ -549,7 +546,7 @@ Object *Lexer::getObj(Object *obj, int objNum) {
   case '{':
   case '}':
     error(errSyntaxError, getPos(), "Illegal character '{0:c}'", c);
-    obj->initError();
+    return Object(objError);
     break;
 
   // command
@@ -567,21 +564,21 @@ Object *Lexer::getObj(Object *obj, int objNum) {
     }
     *p = '\0';
     if (tokBuf[0] == 't' && !strcmp(tokBuf, "true")) {
-      obj->initBool(gTrue);
+      return Object(gTrue);
     } else if (tokBuf[0] == 'f' && !strcmp(tokBuf, "false")) {
-      obj->initBool(gFalse);
+      return Object(gFalse);
     } else if (tokBuf[0] == 'n' && !strcmp(tokBuf, "null")) {
-      obj->initNull();
+      return Object(objNull);
     } else {
-      obj->initCmd(tokBuf);
+      return Object(objCmd, tokBuf);
     }
     break;
   }
 
-  return obj;
+  return Object();
 }
 
-Object *Lexer::getObj(Object *obj, const char *cmdA, int objNum) {
+Object Lexer::getObj(const char *cmdA, int objNum) {
   char *p;
   int c;
   GBool comment;
@@ -594,7 +591,7 @@ Object *Lexer::getObj(Object *obj, const char *cmdA, int objNum) {
   while (strcmp(cmdA, cmd1) && (objNum < 0 || (xref && xref->getNumEntry(getPos()) == objNum))) {
     while (1) {
       if ((c = getChar()) == EOF) {
-        return obj->initEOF();
+        return Object(objEOF);
       }
       if (comment) {
         if (c == '\r' || c == '\n') {
@@ -618,9 +615,8 @@ Object *Lexer::getObj(Object *obj, const char *cmdA, int objNum) {
     }
     *p = '\0';
   }
-  obj->initCmd(tokBuf);
-  
-  return obj;
+
+  return Object(objCmd, tokBuf);
 }
 
 void Lexer::skipToNextLine() {
diff --git a/poppler/Lexer.h b/poppler/Lexer.h
index 02b6cdc6..7792abb0 100644
--- a/poppler/Lexer.h
+++ b/poppler/Lexer.h
@@ -56,8 +56,9 @@ public:
   ~Lexer();
 
   // Get the next object from the input stream.
-  Object *getObj(Object *obj, int objNum = -1);
-  Object *getObj(Object *obj, const char *cmdA, int objNum);
+  Object getObj(int objNum = -1);
+  Object getObj(const char *cmdA, int objNum);
+  template<typename T> Object getObj(T) = delete;
 
   // Skip to the beginning of the next line in the input stream.
   void skipToNextLine();
diff --git a/poppler/Linearization.cc b/poppler/Linearization.cc
index be041f96..1028d4ff 100644
--- a/poppler/Linearization.cc
+++ b/poppler/Linearization.cc
@@ -20,36 +20,26 @@
 Linearization::Linearization (BaseStream *str)
 {
   Parser *parser;
-  Object obj1, obj2, obj3, obj5;
-
-  linDict.initNull();
 
   str->reset();
-  obj1.initNull();
   parser = new Parser(NULL,
-      new Lexer(NULL, str->makeSubStream(str->getStart(), gFalse, 0, &obj1)),
+      new Lexer(NULL, str->makeSubStream(str->getStart(), gFalse, 0, Object(objNull))),
       gFalse);
-  parser->getObj(&obj1);
-  parser->getObj(&obj2);
-  parser->getObj(&obj3);
-  parser->getObj(&linDict);
+  Object obj1 = parser->getObj();
+  Object obj2 = parser->getObj();
+  Object obj3 = parser->getObj();
+  linDict = parser->getObj();
   if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && linDict.isDict()) {
-    linDict.dictLookup("Linearized", &obj5);
+    Object obj5 = linDict.dictLookup("Linearized");
     if (!(obj5.isNum() && obj5.getNum() > 0)) {
-       linDict.free();
-       linDict.initNull();
+       linDict.setToNull();
     }
-    obj5.free();
   }
-  obj3.free();
-  obj2.free();
-  obj1.free();
   delete parser;
 }
 
 Linearization:: ~Linearization()
 {
-  linDict.free();
 }
 
 Guint Linearization::getLength()
@@ -72,17 +62,15 @@ Guint Linearization::getHintsOffset()
 
   Object obj1, obj2;
   if (linDict.isDict() &&
-      linDict.dictLookup("H", &obj1)->isArray() &&
+      (obj1 = linDict.dictLookup("H"), obj1.isArray()) &&
       obj1.arrayGetLength()>=2 &&
-      obj1.arrayGet(0, &obj2)->isInt() &&
+      (obj2 = obj1.arrayGet(0), obj2.isInt()) &&
       obj2.getInt() > 0) {
     hintsOffset = obj2.getInt();
   } else {
     error(errSyntaxWarning, -1, "Hints table offset in linearization table is invalid");
     hintsOffset = 0;
   }
-  obj2.free();
-  obj1.free();
 
   return hintsOffset;
 }
@@ -93,17 +81,15 @@ Guint Linearization::getHintsLength()
 
   Object obj1, obj2;
   if (linDict.isDict() &&
-      linDict.dictLookup("H", &obj1)->isArray() &&
+      (obj1 = linDict.dictLookup("H"), obj1.isArray()) &&
       obj1.arrayGetLength()>=2 &&
-      obj1.arrayGet(1, &obj2)->isInt() &&
+      (obj2 = obj1.arrayGet(1), obj2.isInt()) &&
       obj2.getInt() > 0) {
     hintsLength = obj2.getInt();
   } else {
     error(errSyntaxWarning, -1, "Hints table length in linearization table is invalid");
     hintsLength = 0;
   }
-  obj2.free();
-  obj1.free();
 
   return hintsLength;
 }
@@ -112,20 +98,18 @@ Guint Linearization::getHintsOffset2()
 {
   int hintsOffset2 = 0; // default to 0
 
-  Object obj1, obj2;
+  Object obj1;
   if (linDict.isDict() &&
-      linDict.dictLookup("H", &obj1)->isArray() &&
+      (obj1 = linDict.dictLookup("H"), obj1.isArray()) &&
       obj1.arrayGetLength()>=4) {
-    if (obj1.arrayGet(2, &obj2)->isInt() &&
-        obj2.getInt() > 0) {
+    Object obj2 = obj1.arrayGet(2);
+    if (obj2.isInt() && obj2.getInt() > 0) {
       hintsOffset2 = obj2.getInt();
     } else {
       error(errSyntaxWarning, -1, "Second hints table offset in linearization table is invalid");
       hintsOffset2 = 0;
     }
   }
-  obj2.free();
-  obj1.free();
 
   return hintsOffset2;
 }
@@ -134,20 +118,18 @@ Guint Linearization::getHintsLength2()
 {
   int hintsLength2 = 0; // default to 0
 
-  Object obj1, obj2;
+  Object obj1;
   if (linDict.isDict() &&
-      linDict.dictLookup("H", &obj1)->isArray() &&
+      (obj1 = linDict.dictLookup("H"), obj1.isArray()) &&
       obj1.arrayGetLength()>=4) {
-    if (obj1.arrayGet(3, &obj2)->isInt() &&
-        obj2.getInt() > 0) {
+    Object obj2 = obj1.arrayGet(3);
+    if (obj2.isInt() && obj2.getInt() > 0) {
       hintsLength2 = obj2.getInt();
     } else {
       error(errSyntaxWarning, -1, "Second hints table length in linearization table is invalid");
       hintsLength2 = 0;
     }
   }
-  obj2.free();
-  obj1.free();
 
   return hintsLength2;
 }
diff --git a/poppler/Link.cc b/poppler/Link.cc
index d4680dbc..be92f962 100644
--- a/poppler/Link.cc
+++ b/poppler/Link.cc
@@ -64,7 +64,6 @@ LinkAction *LinkAction::parseDest(Object *obj) {
 
 LinkAction *LinkAction::parseAction(Object *obj, GooString *baseURI) {
   LinkAction *action;
-  Object obj2, obj3, obj4;
 
   if (!obj->isDict()) {
       error(errSyntaxWarning, -1, "parseAction: Bad annotation action for URI '{0:s}'",
@@ -72,21 +71,18 @@ LinkAction *LinkAction::parseAction(Object *obj, GooString *baseURI) {
       return NULL;
   }
 
-  obj->dictLookup("S", &obj2);
+  Object obj2 = obj->dictLookup("S");
 
   // GoTo action
   if (obj2.isName("GoTo")) {
-    obj->dictLookup("D", &obj3);
+    Object obj3 = obj->dictLookup("D");
     action = new LinkGoTo(&obj3);
-    obj3.free();
 
   // GoToR action
   } else if (obj2.isName("GoToR")) {
-    obj->dictLookup("F", &obj3);
-    obj->dictLookup("D", &obj4);
+    Object obj3 = obj->dictLookup("F");
+    Object obj4 = obj->dictLookup("D");
     action = new LinkGoToR(&obj3, &obj4);
-    obj3.free();
-    obj4.free();
 
   // Launch action
   } else if (obj2.isName("Launch")) {
@@ -94,15 +90,13 @@ LinkAction *LinkAction::parseAction(Object *obj, GooString *baseURI) {
 
   // URI action
   } else if (obj2.isName("URI")) {
-    obj->dictLookup("URI", &obj3);
+    Object obj3 = obj->dictLookup("URI");
     action = new LinkURI(&obj3, baseURI);
-    obj3.free();
 
   // Named action
   } else if (obj2.isName("Named")) {
-    obj->dictLookup("N", &obj3);
+    Object obj3 = obj->dictLookup("N");
     action = new LinkNamed(&obj3);
-    obj3.free();
 
   // Movie action
   } else if (obj2.isName("Movie")) {
@@ -118,9 +112,8 @@ LinkAction *LinkAction::parseAction(Object *obj, GooString *baseURI) {
 
   // JavaScript action
   } else if (obj2.isName("JavaScript")) {
-    obj->dictLookup("JS", &obj3);
+    Object obj3 = obj->dictLookup("JS");
     action = new LinkJavaScript(&obj3);
-    obj3.free();
 
   // Set-OCG-State action
   } else if (obj2.isName("SetOCGState")) {
@@ -137,8 +130,6 @@ LinkAction *LinkAction::parseAction(Object *obj, GooString *baseURI) {
     action = NULL;
   }
 
-  obj2.free();
-
   if (action && !action->isOk()) {
     delete action;
     return NULL;
@@ -151,8 +142,6 @@ LinkAction *LinkAction::parseAction(Object *obj, GooString *baseURI) {
 //------------------------------------------------------------------------
 
 LinkDest::LinkDest(Array *a) {
-  Object obj1, obj2;
-
   // initialize fields
   left = bottom = right = top = zoom = 0;
   changeLeft = changeTop = changeZoom = gFalse;
@@ -163,7 +152,7 @@ LinkDest::LinkDest(Array *a) {
     error(errSyntaxWarning, -1, "Annotation destination array is too short");
     return;
   }
-  a->getNF(0, &obj1);
+  Object obj1 = a->getNF(0);
   if (obj1.isInt()) {
     pageNum = obj1.getInt() + 1;
     pageIsRef = gFalse;
@@ -173,12 +162,11 @@ LinkDest::LinkDest(Array *a) {
     pageIsRef = gTrue;
   } else {
     error(errSyntaxWarning, -1, "Bad annotation destination");
-    goto err2;
+    return;
   }
-  obj1.free();
 
   // get destination type
-  a->get(1, &obj1);
+  obj1 = a->get(1);
 
   // XYZ link
   if (obj1.isName("XYZ")) {
@@ -186,7 +174,7 @@ LinkDest::LinkDest(Array *a) {
     if (a->getLength() < 3) {
       changeLeft = gFalse;
     } else {
-      a->get(2, &obj2);
+      Object obj2 = a->get(2);
       if (obj2.isNull()) {
 	changeLeft = gFalse;
       } else if (obj2.isNum()) {
@@ -194,14 +182,13 @@ LinkDest::LinkDest(Array *a) {
 	left = obj2.getNum();
       } else {
 	error(errSyntaxWarning, -1, "Bad annotation destination position");
-	goto err1;
+	return;
       }
-      obj2.free();
     }
     if (a->getLength() < 4) {
       changeTop = gFalse;
     } else {
-      a->get(3, &obj2);
+      Object obj2 = a->get(3);
       if (obj2.isNull()) {
 	changeTop = gFalse;
       } else if (obj2.isNum()) {
@@ -209,14 +196,13 @@ LinkDest::LinkDest(Array *a) {
 	top = obj2.getNum();
       } else {
 	error(errSyntaxWarning, -1, "Bad annotation destination position");
-	goto err1;
+	return;
       }
-      obj2.free();
     }
     if (a->getLength() < 5) {
       changeZoom = gFalse;
     } else {
-      a->get(4, &obj2);
+      Object obj2 = a->get(4);
       if (obj2.isNull()) {
 	changeZoom = gFalse;
       } else if (obj2.isNum()) {
@@ -224,9 +210,8 @@ LinkDest::LinkDest(Array *a) {
 	changeZoom = (zoom == 0) ? gFalse : gTrue;
       } else {
 	error(errSyntaxWarning, -1, "Bad annotation destination position");
-	goto err1;
+	return;
       }
-      obj2.free();
     }
 
   // Fit link
@@ -239,7 +224,7 @@ LinkDest::LinkDest(Array *a) {
     if (a->getLength() < 3) {
       changeTop = gFalse;
     } else {
-      a->get(2, &obj2);
+      Object obj2 = a->get(2);
       if (obj2.isNull()) {
 	changeTop = gFalse;
       } else if (obj2.isNum()) {
@@ -249,17 +234,16 @@ LinkDest::LinkDest(Array *a) {
 	error(errSyntaxWarning, -1, "Bad annotation destination position");
 	kind = destFit;
       }
-      obj2.free();
     }
 
   // FitV link
   } else if (obj1.isName("FitV")) {
     if (a->getLength() < 3) {
       error(errSyntaxWarning, -1, "Annotation destination array is too short");
-      goto err2;
+      return;
     }
     kind = destFitV;
-    a->get(2, &obj2);
+    Object obj2 = a->get(2);
     if (obj2.isNull()) {
       changeLeft = gFalse;
     } else if (obj2.isNum()) {
@@ -269,43 +253,42 @@ LinkDest::LinkDest(Array *a) {
       error(errSyntaxWarning, -1, "Bad annotation destination position");
       kind = destFit;
     }
-    obj2.free();
 
   // FitR link
   } else if (obj1.isName("FitR")) {
     if (a->getLength() < 6) {
       error(errSyntaxWarning, -1, "Annotation destination array is too short");
-      goto err2;
+      return;
     }
     kind = destFitR;
-    if (a->get(2, &obj2)->isNum()) {
+    Object obj2 = a->get(2);
+    if (obj2.isNum()) {
       left = obj2.getNum();
     } else {
       error(errSyntaxWarning, -1, "Bad annotation destination position");
       kind = destFit;
     }
-    obj2.free();
-    if (a->get(3, &obj2)->isNum()) {
+    obj2 = a->get(3);
+    if (obj2.isNum()) {
       bottom = obj2.getNum();
     } else {
       error(errSyntaxWarning, -1, "Bad annotation destination position");
       kind = destFit;
     }
-    obj2.free();
-    if (a->get(4, &obj2)->isNum()) {
+    obj2 = a->get(4);
+    if (obj2.isNum()) {
       right = obj2.getNum();
     } else {
       error(errSyntaxWarning, -1, "Bad annotation destination position");
       kind = destFit;
     }
-    obj2.free();
-    if (a->get(5, &obj2)->isNum()) {
+    obj2 = a->get(5);
+    if (obj2.isNum()) {
       top = obj2.getNum();
     } else {
       error(errSyntaxWarning, -1, "Bad annotation destination position");
       kind = destFit;
     }
-    obj2.free();
 
   // FitB link
   } else if (obj1.isName("FitB")) {
@@ -315,10 +298,10 @@ LinkDest::LinkDest(Array *a) {
   } else if (obj1.isName("FitBH")) {
     if (a->getLength() < 3) {
       error(errSyntaxWarning, -1, "Annotation destination array is too short");
-      goto err2;
+      return;
     }
     kind = destFitBH;
-    a->get(2, &obj2);
+    Object obj2 = a->get(2);
     if (obj2.isNull()) {
       changeTop = gFalse;
     } else if (obj2.isNum()) {
@@ -328,16 +311,15 @@ LinkDest::LinkDest(Array *a) {
       error(errSyntaxWarning, -1, "Bad annotation destination position");
       kind = destFit;
     }
-    obj2.free();
 
   // FitBV link
   } else if (obj1.isName("FitBV")) {
     if (a->getLength() < 3) {
       error(errSyntaxWarning, -1, "Annotation destination array is too short");
-      goto err2;
+      return;
     }
     kind = destFitBV;
-    a->get(2, &obj2);
+    Object obj2 = a->get(2);
     if (obj2.isNull()) {
       changeLeft = gFalse;
     } else if (obj2.isNum()) {
@@ -347,22 +329,14 @@ LinkDest::LinkDest(Array *a) {
       error(errSyntaxWarning, -1, "Bad annotation destination position");
       kind = destFit;
     }
-    obj2.free();
 
   // unknown link kind
   } else {
     error(errSyntaxWarning, -1, "Unknown annotation destination type");
-    goto err2;
   }
 
-  obj1.free();
   ok = gTrue;
   return;
-
- err1:
-  obj2.free();
- err2:
-  obj1.free();
 }
 
 LinkDest::LinkDest(LinkDest *dest) {
@@ -428,10 +402,9 @@ LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) {
   namedDest = NULL;
 
   // get file name
-  Object obj1;
-  if (getFileSpecNameForPlatform (fileSpecObj, &obj1)) {
+  Object obj1 = getFileSpecNameForPlatform (fileSpecObj);
+  if (obj1.isString()) {
     fileName = obj1.getString()->copy();
-    obj1.free();
   }
 
   // named destination
@@ -469,54 +442,49 @@ LinkGoToR::~LinkGoToR() {
 //------------------------------------------------------------------------
 
 LinkLaunch::LinkLaunch(Object *actionObj) {
-  Object obj1, obj2, obj3;
 
   fileName = NULL;
   params = NULL;
 
   if (actionObj->isDict()) {
-    if (!actionObj->dictLookup("F", &obj1)->isNull()) {
-      if (getFileSpecNameForPlatform (&obj1, &obj3)) {
+    Object obj1 = actionObj->dictLookup("F");
+    if (!obj1.isNull()) {
+      Object obj3 = getFileSpecNameForPlatform (&obj1);
+      if (obj3.isString()) {
 	fileName = obj3.getString()->copy();
-	obj3.free();
       }
     } else {
-      obj1.free();
 #ifdef _WIN32
       if (actionObj->dictLookup("Win", &obj1)->isDict()) {
 	obj1.dictLookup("F", &obj2);
 	if (getFileSpecNameForPlatform (&obj2, &obj3)) {
 	  fileName = obj3.getString()->copy();
-	  obj3.free();
 	}
-	obj2.free();
 	if (obj1.dictLookup("P", &obj2)->isString()) {
 	  params = obj2.getString()->copy();
 	}
-	obj2.free();
       } else {
 	error(errSyntaxWarning, -1, "Bad launch-type link action");
       }
 #else
       //~ This hasn't been defined by Adobe yet, so assume it looks
       //~ just like the Win dictionary until they say otherwise.
-      if (actionObj->dictLookup("Unix", &obj1)->isDict()) {
-	obj1.dictLookup("F", &obj2);
-	if (getFileSpecNameForPlatform (&obj2, &obj3)) {
+      obj1 = actionObj->dictLookup("Unix");
+      if (obj1.isDict()) {
+	Object obj2 = obj1.dictLookup("F");
+	Object obj3 = getFileSpecNameForPlatform (&obj2);
+	if (obj3.isString()) {
 	  fileName = obj3.getString()->copy();
-	  obj3.free();
 	}
-	obj2.free();
-	if (obj1.dictLookup("P", &obj2)->isString()) {
+	obj2 = obj1.dictLookup("P");
+	if (obj2.isString()) {
 	  params = obj2.getString()->copy();
 	}
-	obj2.free();
       } else {
 	error(errSyntaxWarning, -1, "Bad launch-type link action");
       }
 #endif
     }
-    obj1.free();
   }
 }
 
@@ -601,23 +569,23 @@ LinkMovie::LinkMovie(Object *obj) {
   annotRef.num = -1;
   annotTitle = NULL;
 
-  Object tmp;
-  if (obj->dictLookupNF("Annotation", &tmp)->isRef()) {
+  Object tmp = obj->dictLookupNF("Annotation");
+  if (tmp.isRef()) {
     annotRef = tmp.getRef();
   }
-  tmp.free();
 
-  if (obj->dictLookup("T", &tmp)->isString()) {
+  tmp = obj->dictLookup("T");
+  if (tmp.isString()) {
     annotTitle = tmp.getString()->copy();
   }
-  tmp.free();
 
   if ((annotTitle == NULL) && (annotRef.num == -1)) {
     error(errSyntaxError, -1,
 	  "Movie action is missing both the Annot and T keys");
   }
 
-  if (obj->dictLookup("Operation", &tmp)->isName()) {
+  tmp = obj->dictLookup("Operation");
+  if (tmp.isName()) {
     char *name = tmp.getName();
     
     if (!strcmp(name, "Play")) {
@@ -633,7 +601,6 @@ LinkMovie::LinkMovie(Object *obj) {
       operation = operationTypeResume;
     }
   }
-  tmp.free();
 }
 
 LinkMovie::~LinkMovie() {
@@ -654,35 +621,29 @@ LinkSound::LinkSound(Object *soundObj) {
   sound = NULL;
   if (soundObj->isDict())
   {
-    Object tmp;
     // volume
-    soundObj->dictLookup("Volume", &tmp);
+    Object tmp = soundObj->dictLookup("Volume");
     if (tmp.isNum()) {
       volume = tmp.getNum();
     }
-    tmp.free();
     // sync
-    soundObj->dictLookup("Synchronous", &tmp);
+    tmp = soundObj->dictLookup("Synchronous");
     if (tmp.isBool()) {
       sync = tmp.getBool();
     }
-    tmp.free();
     // repeat
-    soundObj->dictLookup("Repeat", &tmp);
+    tmp = soundObj->dictLookup("Repeat");
     if (tmp.isBool()) {
       repeat = tmp.getBool();
     }
-    tmp.free();
     // mix
-    soundObj->dictLookup("Mix", &tmp);
+    tmp = soundObj->dictLookup("Mix");
     if (tmp.isBool()) {
       mix = tmp.getBool();
     }
-    tmp.free();
     // 'Sound' object
-    soundObj->dictLookup("Sound", &tmp);
+    tmp = soundObj->dictLookup("Sound");
     sound = Sound::parseSound(&tmp);
-    tmp.free();
   }
 }
 
@@ -701,9 +662,8 @@ LinkRendition::LinkRendition(Object *obj) {
   int operationCode = -1;
 
   if (obj->isDict()) {
-    Object tmp;
-
-    if (!obj->dictLookup("JS", &tmp)->isNull()) {
+    Object tmp = obj->dictLookup("JS");
+    if (!tmp.isNull()) {
       if (tmp.isString()) {
         js = new GooString(tmp.getString());
       } else if (tmp.isStream()) {
@@ -714,9 +674,9 @@ LinkRendition::LinkRendition(Object *obj) {
         error(errSyntaxWarning, -1, "Invalid Rendition Action: JS not string or stream");
       }
     }
-    tmp.free();
 
-    if (obj->dictLookup("OP", &tmp)->isInt()) {
+    tmp = obj->dictLookup("OP");
+    if (tmp.isInt()) {
       operationCode = tmp.getInt();
       if (!js && (operationCode < 0 || operationCode > 4)) {
         error(errSyntaxWarning, -1, "Invalid Rendition Action: unrecognized operation valued: {0:d}", operationCode);
@@ -724,16 +684,18 @@ LinkRendition::LinkRendition(Object *obj) {
         Object obj1;
 
         // retrieve rendition object
-        if (obj->dictLookup("R", &renditionObj)->isDict()) {
+        renditionObj = obj->dictLookup("R");
+        if (renditionObj.isDict()) {
           media = new MediaRendition(&renditionObj);
 	} else if (operationCode == 0 || operationCode == 4) {
           error(errSyntaxWarning, -1, "Invalid Rendition Action: no R field with op = {0:d}", operationCode);
-	  renditionObj.free();
+	  renditionObj.setToNull();
 	}
 
-	if (!obj->dictLookupNF("AN", &screenRef)->isRef() && operation >= 0 && operation <= 4) {
+	screenRef = obj->dictLookupNF("AN");
+	if (!screenRef.isRef() && operation >= 0 && operation <= 4) {
 	  error(errSyntaxWarning, -1, "Invalid Rendition Action: no AN field with op = {0:d}", operationCode);
-	  screenRef.free();
+	  screenRef.setToNull();
 	}
       }
 
@@ -757,18 +719,12 @@ LinkRendition::LinkRendition(Object *obj) {
     } else if (!js) {
       error(errSyntaxWarning, -1, "Invalid Rendition action: no OP or JS field defined");
     }
-    tmp.free();
   }
 }
 
 LinkRendition::~LinkRendition() {
-  renditionObj.free();
-  screenRef.free();
-
-  if (js)
-    delete js;
-  if (media)
-    delete media;
+  delete js;
+  delete media;
 }
 
 
@@ -799,18 +755,15 @@ LinkJavaScript::~LinkJavaScript() {
 // LinkOCGState
 //------------------------------------------------------------------------
 LinkOCGState::LinkOCGState(Object *obj) {
-  Object obj1;
-
   stateList = new GooList();
   preserveRB = gTrue;
 
-  if (obj->dictLookup("State", &obj1)->isArray()) {
+  Object obj1 = obj->dictLookup("State");
+  if (obj1.isArray()) {
     StateList *stList = NULL;
 
     for (int i = 0; i < obj1.arrayGetLength(); ++i) {
-      Object obj2;
-
-      obj1.arrayGetNF(i, &obj2);
+      Object obj2 = obj1.arrayGetNF(i);
       if (obj2.isName()) {
         if (stList)
 	  stateList->append(stList);
@@ -842,7 +795,6 @@ LinkOCGState::LinkOCGState(Object *obj) {
       } else {
         error(errSyntaxWarning, -1, "Invalid item in OCG Action State array");
       }
-      obj2.free();
     }
     // Add the last group
     if (stList)
@@ -852,12 +804,11 @@ LinkOCGState::LinkOCGState(Object *obj) {
     delete stateList;
     stateList = NULL;
   }
-  obj1.free();
 
-  if (obj->dictLookup("PreserveRB", &obj1)->isBool()) {
+  obj1 = obj->dictLookup("PreserveRB");
+  if (obj1.isBool()) {
     preserveRB = obj1.getBool();
   }
-  obj1.free();
 }
 
 LinkOCGState::~LinkOCGState() {
diff --git a/poppler/Movie.cc b/poppler/Movie.cc
index 7775eb50..fa709b3b 100644
--- a/poppler/Movie.cc
+++ b/poppler/Movie.cc
@@ -47,9 +47,8 @@ MovieActivationParameters::~MovieActivationParameters() {
 }
 
 void MovieActivationParameters::parseMovieActivation(Object* aDict) {
-  Object obj1;
-
-  if (!aDict->dictLookup("Start", &obj1)->isNull()) {
+  Object obj1 = aDict->dictLookup("Start");
+  if (obj1.isNull()) {
     if (obj1.isInt()) {
       // If it is representable as an integer (subject to the implementation limit for
       // integers, as described in Appendix C), it should be specified as such.
@@ -64,26 +63,23 @@ void MovieActivationParameters::parseMovieActivation(Object* aDict) {
     } else if (obj1.isArray()) {
       Array* a = obj1.getArray();
 
-      Object tmp;
-      a->get(0, &tmp);
+      Object tmp = a->get(0);
       if (tmp.isInt()) {
         start.units = tmp.getInt();
       }
       if (tmp.isString()) {
         // UNSUPPORTED
       }
-      tmp.free();
 
-      a->get(1, &tmp);
+      tmp = a->get(1);
       if (tmp.isInt()) {
         start.units_per_second = tmp.getInt();
       }
-      tmp.free();
     }
   }
-  obj1.free();
 
-  if (!aDict->dictLookup("Duration", &obj1)->isNull()) {
+  obj1 = aDict->dictLookup("Duration");
+  if (obj1.isNull()) {
     if (obj1.isInt()) {
       duration.units = obj1.getInt();
     } else if (obj1.isString()) {
@@ -91,47 +87,44 @@ void MovieActivationParameters::parseMovieActivation(Object* aDict) {
     } else if (obj1.isArray()) {
       Array* a = obj1.getArray();
 
-      Object tmp;
-      a->get(0, &tmp);
+      Object tmp = a->get(0);
       if (tmp.isInt()) {
         duration.units = tmp.getInt();
       }
       if (tmp.isString()) {
         // UNSUPPORTED
       }
-      tmp.free();
 
-      a->get(1, &tmp);
+      tmp = a->get(1);
       if (tmp.isInt()) {
         duration.units_per_second = tmp.getInt();
       }
-      tmp.free();
     }
   }
-  obj1.free();
 
-  if (aDict->dictLookup("Rate", &obj1)->isNum()) {
+  obj1 = aDict->dictLookup("Rate");
+  if (obj1.isNum()) {
     rate = obj1.getNum();
   }
-  obj1.free();
 
-  if (aDict->dictLookup("Volume", &obj1)->isNum()) {
+  obj1 = aDict->dictLookup("Volume");
+  if (obj1.isNum()) {
     // convert volume to [0 100]
     volume = int((obj1.getNum() + 1.0) * 50);
   }
-  obj1.free();
 
-  if (aDict->dictLookup("ShowControls", &obj1)->isBool()) {
+  obj1 = aDict->dictLookup("ShowControls");
+  if (obj1.isBool()) {
     showControls = obj1.getBool();
   }
-  obj1.free();
 
-  if (aDict->dictLookup("Synchronous", &obj1)->isBool()) {
+  obj1 = aDict->dictLookup("Synchronous");
+  if (obj1.isBool()) {
     synchronousPlay = obj1.getBool();
   }
-  obj1.free();
 
-  if (aDict->dictLookup("Mode", &obj1)->isName()) {
+  obj1 = aDict->dictLookup("Mode");
+  if (obj1.isName()) {
     char* name = obj1.getName();
     if (!strcmp(name, "Once")) {
       repeatMode = repeatModeOnce;
@@ -143,43 +136,40 @@ void MovieActivationParameters::parseMovieActivation(Object* aDict) {
       repeatMode = repeatModePalindrome;
     }
   }
-  obj1.free();
 
-  if (aDict->dictLookup("FWScale", &obj1)->isArray()) {
+  obj1 = aDict->dictLookup("FWScale");
+  if (obj1.isArray()) {
     // the presence of that entry implies that the movie is to be played
     // in a floating window
     floatingWindow = gTrue;
 
     Array* scale = obj1.getArray();
     if (scale->getLength() >= 2) {
-      Object tmp;
-      if (scale->get(0, &tmp)->isInt()) {
+      Object tmp = scale->get(1);
+      if (tmp.isInt()) {
         znum = tmp.getInt();
       }
-      tmp.free();
-      if (scale->get(1, &tmp)->isInt()) {
+      tmp = scale->get(1);
+      if (tmp.isInt()) {
         zdenum = tmp.getInt();
       }
-      tmp.free();
     }
   }
-  obj1.free();
 
-  if (aDict->dictLookup("FWPosition", &obj1)->isArray()) {
+  obj1 = aDict->dictLookup("FWPosition");
+  if (obj1.isArray()) {
     Array* pos = obj1.getArray();
     if (pos->getLength() >= 2) {
-      Object tmp;
-      if (pos->get(0, &tmp)->isNum()) {
+      Object tmp = pos->get(0);
+      if (tmp.isNum()) {
         xPosition = tmp.getNum();
       }
-      tmp.free();
-      if (pos->get(1, &tmp)->isNum()) {
+      tmp = pos->get(1);
+      if (tmp.isNum()) {
         yPosition = tmp.getNum();
       }
-      tmp.free();
     }
   }
-  obj1.free();
 }
 
 void Movie::parseMovie (Object *movieDict) {
@@ -189,59 +179,55 @@ void Movie::parseMovie (Object *movieDict) {
   height = -1;
   showPoster = gFalse;
 
-  Object obj1, obj2;
-  if (getFileSpecNameForPlatform(movieDict->dictLookup("F", &obj1), &obj2)) {
+  Object obj1 = movieDict->dictLookup("F");
+  Object obj2 = getFileSpecNameForPlatform(&obj1);
+  if (obj2.isString()) {
     fileName = obj2.getString()->copy();
-    obj2.free();
   } else {
     error (errSyntaxError, -1, "Invalid Movie");
     ok = gFalse;
-    obj1.free();
     return;
   }
-  obj1.free();
 
-  if (movieDict->dictLookup("Aspect", &obj1)->isArray()) {
+  obj1 = movieDict->dictLookup("Aspect");
+  if (obj1.isArray()) {
     Array* aspect = obj1.getArray();
     if (aspect->getLength() >= 2) {
-      Object tmp;
-      if( aspect->get(0, &tmp)->isNum() ) {
-        width = (int)floor( aspect->get(0, &tmp)->getNum() + 0.5 );
+      Object tmp = aspect->get(0);
+      if( tmp.isNum() ) {
+        width = (int)floor( tmp.getNum() + 0.5 );
       }
-      tmp.free();
-      if( aspect->get(1, &tmp)->isNum() ) {
-        height = (int)floor( aspect->get(1, &tmp)->getNum() + 0.5 );
+      tmp = aspect->get(1);
+      if( tmp.isNum() ) {
+        height = (int)floor( tmp.getNum() + 0.5 );
       }
-      tmp.free();
     }
   }
-  obj1.free();
 
-  if (movieDict->dictLookup("Rotate", &obj1)->isInt()) {
+  obj1 = movieDict->dictLookup("Rotate");
+  if (obj1.isInt()) {
     // round up to 90°
     rotationAngle = (((obj1.getInt() + 360) % 360) % 90) * 90;
   }
-  obj1.free();
 
   //
   // movie poster
   //
-  if (!movieDict->dictLookupNF("Poster", &poster)->isNull()) {
+  poster = movieDict->dictLookupNF("Poster");
+  if (!poster.isNull()) {
     if (poster.isRef() || poster.isStream()) {
       showPoster = gTrue;
     } else if (poster.isBool()) {
       showPoster = poster.getBool();
-      poster.free();
+      poster.setToNull();
     } else {
-      poster.free();
+      poster.setToNull();
     }
   }
 }
 
 Movie::~Movie() {
-  if (fileName)
-    delete fileName;
-  poster.free();
+  delete fileName;
 }
 
 Movie::Movie(Object *movieDict) {
@@ -274,7 +260,7 @@ Movie::Movie(const Movie &other)
   showPoster = other.showPoster;
   MA = other.MA;
 
-  other.poster.copy(&poster);
+  poster = other.poster.copy();
 
   if (other.fileName)
     fileName = other.fileName->copy();
diff --git a/poppler/Movie.h b/poppler/Movie.h
index 587853e8..c0fcd8f4 100644
--- a/poppler/Movie.h
+++ b/poppler/Movie.h
@@ -83,7 +83,7 @@ class Movie {
   Gushort getRotationAngle() { return rotationAngle; }
   void getAspect (int *widthA, int *heightA) { *widthA = width; *heightA = height; }
 
-  Object *getPoster(Object *obj) { return poster.copy(obj); }
+  Object getPoster() { return poster.copy(); }
   GBool getShowPoster() { return showPoster; }
 
   GBool getUseFloatingWindow() { return MA.floatingWindow; }
diff --git a/poppler/Object.cc b/poppler/Object.cc
index e84abcc2..4fce012d 100644
--- a/poppler/Object.cc
+++ b/poppler/Object.cc
@@ -84,42 +84,18 @@ Object::~Object()
   free();
 }
 
-Object *Object::initArray(XRef *xref) {
-  initObj(objArray);
-  array = new Array(xref);
-  return this;
-}
-
-Object *Object::initDict(XRef *xref) {
-  initObj(objDict);
-  dict = new Dict(xref);
-  return this;
-}
-
-Object *Object::initDict(Dict *dictA) {
-  initObj(objDict);
-  dict = dictA;
-  dict->incRef();
-  return this;
-}
-
-Object *Object::initStream(Stream *streamA) {
-  initObj(objStream);
-  stream = streamA;
-  return this;
-}
-
-Object *Object::copy(Object *obj) const {
+Object Object::copy() const {
   CHECK_NOT_DEAD;
 
-  obj->type = type;
-  obj->real = real; // this is the biggest of the union so it's enough
+  Object obj;
+  obj.type = type;
+  obj.real = real; // this is the biggest of the union so it's enough
   switch (type) {
   case objString:
-    obj->string = string->copy();
+    obj.string = string->copy();
     break;
   case objName:
-    obj->name = copyString(name);
+    obj.cString = copyString(cString);
     break;
   case objArray:
     array->incRef();
@@ -131,7 +107,7 @@ Object *Object::copy(Object *obj) const {
     stream->incRef();
     break;
   case objCmd:
-    obj->cmd = copyString(cmd);
+    obj.cString = copyString(cString);
     break;
   default:
     break;
@@ -142,22 +118,11 @@ Object *Object::copy(Object *obj) const {
   return obj;
 }
 
-Object *Object::shallowCopy(Object *obj)
-{
-  CHECK_NOT_DEAD;
-
-  obj->free();
-  obj->type = type;
-  obj->real = real; // this is the biggest of the union so it's enough
-  type = objDead;
-  return obj;
-}
-
-Object *Object::fetch(XRef *xref, Object *obj, int recursion) {
+Object Object::fetch(XRef *xref, int recursion) const {
   CHECK_NOT_DEAD;
 
   return (type == objRef && xref) ?
-         xref->fetch(ref.num, ref.gen, obj, recursion) : copy(obj);
+         xref->fetch(ref.num, ref.gen, recursion) : copy();
 }
 
 void Object::free() {
@@ -166,7 +131,7 @@ void Object::free() {
     delete string;
     break;
   case objName:
-    gfree(name);
+    gfree(cString);
     break;
   case objArray:
     if (!array->decRef()) {
@@ -184,7 +149,7 @@ void Object::free() {
     }
     break;
   case objCmd:
-    gfree(cmd);
+    gfree(cString);
     break;
   default:
     break;
@@ -219,7 +184,7 @@ void Object::print(FILE *f) {
     fprintf(f, ")");
     break;
   case objName:
-    fprintf(f, "/%s", name);
+    fprintf(f, "/%s", cString);
     break;
   case objNull:
     fprintf(f, "null");
@@ -229,9 +194,8 @@ void Object::print(FILE *f) {
     for (i = 0; i < arrayGetLength(); ++i) {
       if (i > 0)
 	fprintf(f, " ");
-      arrayGetNF(i, &obj);
+      obj = arrayGetNF(i);
       obj.print(f);
-      obj.free();
     }
     fprintf(f, "]");
     break;
@@ -239,9 +203,8 @@ void Object::print(FILE *f) {
     fprintf(f, "<<");
     for (i = 0; i < dictGetLength(); ++i) {
       fprintf(f, " /%s ", dictGetKey(i));
-      dictGetValNF(i, &obj);
+      obj = dictGetValNF(i);
       obj.print(f);
-      obj.free();
     }
     fprintf(f, " >>");
     break;
@@ -252,7 +215,7 @@ void Object::print(FILE *f) {
     fprintf(f, "%d %d R", ref.num, ref.gen);
     break;
   case objCmd:
-    fprintf(f, "%s", cmd);
+    fprintf(f, "%s", cString);
     break;
   case objError:
     fprintf(f, "<error>");
diff --git a/poppler/Object.h b/poppler/Object.h
index 8cda79db..732dac2d 100644
--- a/poppler/Object.h
+++ b/poppler/Object.h
@@ -127,70 +127,61 @@ enum ObjType {
 #define initObj(t) free(); zeroUnion(); type = t
 #endif
 
+#ifdef DEBUG_MEM
+#define constructObj(t) ++numAlloc[type = t]
+#else
+#define constructObj(t) type = t
+#endif
+
 class Object {
 public:
   // clear the anonymous union as best we can -- clear at least a pointer
-  void zeroUnion() { this->name = NULL; }
+  void zeroUnion() { this->cString = NULL; }
 
   // Default constructor.
   Object():
     type(objNone) { zeroUnion(); }
   ~Object();
 
+  explicit Object(GBool boolnA)
+    { constructObj(objBool); booln = boolnA; }
+  explicit Object(int intgA)
+    { constructObj(objInt); intg = intgA; }
+  explicit Object(ObjType typeA)
+    { constructObj(typeA); }
+  explicit Object(double realA)
+    { constructObj(objReal); real = realA; }
+  explicit Object(GooString *stringA)
+    { constructObj(objString); string = stringA; }
+  Object(ObjType typeA, const char *stringA)
+    { constructObj(typeA); cString = copyString(stringA); }
+  explicit Object(long long int64gA)
+    { constructObj(objInt64); int64g = int64gA; }
+  explicit Object(Array *arrayA)
+    { constructObj(objArray); array = arrayA; }
+  explicit Object(Dict *dictA)
+    { constructObj(objDict); dict = dictA; }
+  explicit Object(Stream *streamA)
+    { constructObj(objStream); stream = streamA; }
+  Object(int numA, int genA)
+    { constructObj(objRef); ref.num = numA; ref.gen = genA; }
+  template<typename T> Object(T) = delete;
+
   Object(Object&& other);
   Object& operator=(Object&& other);
 
   Object &operator=(const Object &other) = delete;
   Object(const Object &other) = delete;
 
-  // Initialize an object.
-  Object *initBool(GBool boolnA)
-    { initObj(objBool); booln = boolnA; return this; }
-  Object *initInt(int intgA)
-    { initObj(objInt); intg = intgA; return this; }
-  Object *initReal(double realA)
-    { initObj(objReal); real = realA; return this; }
-  Object *initString(GooString *stringA)
-    { initObj(objString); string = stringA; return this; }
-  Object *initName(const char *nameA)
-    { initObj(objName); name = copyString(nameA); return this; }
-  Object *initNull()
-    { initObj(objNull); return this; }
-  Object *initNullNoFree()
-    {
-      type = objNull;
-#ifdef DEBUG_MEM
-#define initObj(t) ++numAlloc[objNull]
-#endif
-      return this;
-    }
-  Object *initArray(XRef *xref);
-  Object *initDict(XRef *xref);
-  Object *initDict(Dict *dictA);
-  Object *initStream(Stream *streamA);
-  Object *initRef(int numA, int genA)
-    { initObj(objRef); ref.num = numA; ref.gen = genA; return this; }
-  Object *initCmd(char *cmdA)
-    { initObj(objCmd); cmd = copyString(cmdA); return this; }
-  Object *initError()
-    { initObj(objError); return this; }
-  Object *initEOF()
-    { initObj(objEOF); return this; }
-  Object *initInt64(long long int64gA)
-    { initObj(objInt64); int64g = int64gA; return this; }
+  // Set object to null.
+  void setToNull() { initObj(objNull); }
 
   // Copy this to obj
-  Object *copy(Object *obj) const;
-
-  // Copy this to obj. This becomes a none object
-  Object *shallowCopy(Object *obj);
+  Object copy() const;
 
   // If object is a Ref, fetch and return the referenced object.
   // Otherwise, return a copy of the object.
-  Object *fetch(XRef *xref, Object *obj, int recursion = 0);
-
-  // Free object contents.
-  void free();
+  Object fetch(XRef *xref, int recursion = 0) const;
 
   // Type checking.
   ObjType getType() { CHECK_NOT_DEAD; return type; }
@@ -214,11 +205,11 @@ public:
 
   // Special type checking.
   GBool isName(const char *nameA)
-    { return type == objName && !strcmp(name, nameA); }
+    { return type == objName && !strcmp(cString, nameA); }
   GBool isDict(const char *dictType);
   GBool isStream(char *dictType);
   GBool isCmd(const char *cmdA)
-    { return type == objCmd && !strcmp(cmd, cmdA); }
+    { return type == objCmd && !strcmp(cString, cmdA); }
 
   // Accessors.
   GBool getBool() { OBJECT_TYPE_CHECK(objBool); return booln; }
@@ -234,36 +225,36 @@ public:
   // because the object it's not expected to have a NULL string.
   GooString *takeString() {
     OBJECT_TYPE_CHECK(objString); GooString *s = string; string = NULL; return s; }
-  char *getName() { OBJECT_TYPE_CHECK(objName); return name; }
+  char *getName() { OBJECT_TYPE_CHECK(objName); return cString; }
   Array *getArray() { OBJECT_TYPE_CHECK(objArray); return array; }
   Dict *getDict() { OBJECT_TYPE_CHECK(objDict); return dict; }
   Stream *getStream() { OBJECT_TYPE_CHECK(objStream); return stream; }
   Ref getRef() { OBJECT_TYPE_CHECK(objRef); return ref; }
   int getRefNum() { OBJECT_TYPE_CHECK(objRef); return ref.num; }
   int getRefGen() { OBJECT_TYPE_CHECK(objRef); return ref.gen; }
-  char *getCmd() { OBJECT_TYPE_CHECK(objCmd); return cmd; }
+  char *getCmd() { OBJECT_TYPE_CHECK(objCmd); return cString; }
   long long getInt64() { OBJECT_TYPE_CHECK(objInt64); return int64g; }
   long long getIntOrInt64() { OBJECT_2TYPES_CHECK(objInt, objInt64);
     return type == objInt ? intg : int64g; }
 
   // Array accessors.
   int arrayGetLength();
-  void arrayAdd(Object *elem);
+  void arrayAdd(Object &&elem);
   void arrayRemove(int i);
-  Object *arrayGet(int i, Object *obj, int recursion);
-  Object *arrayGetNF(int i, Object *obj);
+  Object arrayGet(int i, int recursion);
+  Object arrayGetNF(int i);
 
   // Dict accessors.
   int dictGetLength();
-  void dictAdd(char *key, Object *val);
-  void dictSet(const char *key, Object *val);
+  void dictAdd(char *key, Object &&val);
+  void dictSet(const char *key, Object &&val);
   void dictRemove(const char *key);
   GBool dictIs(const char *dictType);
-  Object *dictLookup(const char *key, Object *obj, int recursion = 0);
-  Object *dictLookupNF(const char *key, Object *obj);
+  Object dictLookup(const char *key, int recursion = 0);
+  Object dictLookupNF(const char *key);
   char *dictGetKey(int i);
-  Object *dictGetVal(int i, Object *obj);
-  Object *dictGetValNF(int i, Object *obj);
+  Object dictGetVal(int i);
+  Object dictGetValNF(int i);
 
   // Stream accessors.
   GBool streamIs(char *dictType);
@@ -285,6 +276,15 @@ public:
   static void memCheck(FILE *f);
 
 private:
+  friend class Array; // Needs free and initNullAfterMalloc
+  friend class Dict; // Needs free and initNullAfterMalloc
+  friend class XRef; // Needs free and initNullAfterMalloc
+
+  // Free object contents.
+  void free();
+
+  // Only use if are mallocing Objects
+  void initNullAfterMalloc() { constructObj(objNull); }
 
   ObjType type;			// object type
   union {			// value for each type:
@@ -293,12 +293,11 @@ private:
     long long int64g;           //   64-bit integer
     double real;		//   real
     GooString *string;		//   string
-    char *name;			//   name
+    char *cString;		//   name
     Array *array;		//   array
     Dict *dict;			//   dictionary
     Stream *stream;		//   stream
     Ref ref;			//   indirect reference
-    char *cmd;			//   command
   };
 
 #ifdef DEBUG_MEM
@@ -316,17 +315,17 @@ private:
 inline int Object::arrayGetLength()
   { OBJECT_TYPE_CHECK(objArray); return array->getLength(); }
 
-inline void Object::arrayAdd(Object *elem)
-  { OBJECT_TYPE_CHECK(objArray); array->add(elem); }
+inline void Object::arrayAdd(Object &&elem)
+  { OBJECT_TYPE_CHECK(objArray); array->add(std::move(elem)); }
 
 inline void Object::arrayRemove(int i)
   { OBJECT_TYPE_CHECK(objArray); array->remove(i); }
 
-inline Object *Object::arrayGet(int i, Object *obj, int recursion = 0)
-  { OBJECT_TYPE_CHECK(objArray); return array->get(i, obj, recursion); }
+inline Object Object::arrayGet(int i, int recursion = 0)
+  { OBJECT_TYPE_CHECK(objArray); return array->get(i, recursion); }
 
-inline Object *Object::arrayGetNF(int i, Object *obj)
-  { OBJECT_TYPE_CHECK(objArray); return array->getNF(i, obj); }
+inline Object Object::arrayGetNF(int i)
+  { OBJECT_TYPE_CHECK(objArray); return array->getNF(i); }
 
 //------------------------------------------------------------------------
 // Dict accessors.
@@ -337,11 +336,11 @@ inline Object *Object::arrayGetNF(int i, Object *obj)
 inline int Object::dictGetLength()
   { OBJECT_TYPE_CHECK(objDict); return dict->getLength(); }
 
-inline void Object::dictAdd(char *key, Object *val)
-  { OBJECT_TYPE_CHECK(objDict); dict->add(key, val); }
+inline void Object::dictAdd(char *key, Object &&val)
+  { OBJECT_TYPE_CHECK(objDict); dict->add(key, std::move(val)); }
 
-inline void Object::dictSet(const char *key, Object *val)
-  { OBJECT_TYPE_CHECK(objDict); dict->set(key, val); }
+inline void Object::dictSet(const char *key, Object &&val)
+  { OBJECT_TYPE_CHECK(objDict); dict->set(key, std::move(val)); }
 
 inline void Object::dictRemove(const char *key)
   { OBJECT_TYPE_CHECK(objDict); dict->remove(key); }
@@ -352,20 +351,20 @@ inline GBool Object::dictIs(const char *dictType)
 inline GBool Object::isDict(const char *dictType)
   { return type == objDict && dictIs(dictType); }
 
-inline Object *Object::dictLookup(const char *key, Object *obj, int recursion)
-  { OBJECT_TYPE_CHECK(objDict); return dict->lookup(key, obj, recursion); }
+inline Object Object::dictLookup(const char *key, int recursion)
+  { OBJECT_TYPE_CHECK(objDict); return dict->lookup(key, recursion); }
 
-inline Object *Object::dictLookupNF(const char *key, Object *obj)
-  { OBJECT_TYPE_CHECK(objDict); return dict->lookupNF(key, obj); }
+inline Object Object::dictLookupNF(const char *key)
+  { OBJECT_TYPE_CHECK(objDict); return dict->lookupNF(key); }
 
 inline char *Object::dictGetKey(int i)
   { OBJECT_TYPE_CHECK(objDict); return dict->getKey(i); }
 
-inline Object *Object::dictGetVal(int i, Object *obj)
-  { OBJECT_TYPE_CHECK(objDict); return dict->getVal(i, obj); }
+inline Object Object::dictGetVal(int i)
+  { OBJECT_TYPE_CHECK(objDict); return dict->getVal(i); }
 
-inline Object *Object::dictGetValNF(int i, Object *obj)
-  { OBJECT_TYPE_CHECK(objDict); return dict->getValNF(i, obj); }
+inline Object Object::dictGetValNF(int i)
+  { OBJECT_TYPE_CHECK(objDict); return dict->getValNF(i); }
 
 //------------------------------------------------------------------------
 // Stream accessors.
diff --git a/poppler/OptionalContent.cc b/poppler/OptionalContent.cc
index dd839707..d2e878e4 100644
--- a/poppler/OptionalContent.cc
+++ b/poppler/OptionalContent.cc
@@ -43,50 +43,40 @@ OCGs::OCGs(Object *ocgObject, XRef *xref) :
   optionalContentGroups = new GooList();
   display = NULL;
 
-  Object ocgList;
-  ocgObject->dictLookup("OCGs", &ocgList);
+  Object ocgList = ocgObject->dictLookup("OCGs");
   if (!ocgList.isArray()) {
     error(errSyntaxError, -1, "Expected the optional content group list, but wasn't able to find it, or it isn't an Array");
-    ocgList.free();
     ok = gFalse;
     return;
   }
 
   // we now enumerate over the ocgList, and build up the optionalContentGroups list.
   for(int i = 0; i < ocgList.arrayGetLength(); ++i) {
-    Object ocg;
-    ocgList.arrayGet(i, &ocg);
+    Object ocg = ocgList.arrayGet(i);
     if (!ocg.isDict()) {
-      ocg.free();
       break;
     }
     OptionalContentGroup *thisOptionalContentGroup = new OptionalContentGroup(ocg.getDict());
-    ocg.free();
-    ocgList.arrayGetNF(i, &ocg);
+    ocg = ocgList.arrayGetNF(i);
     if (!ocg.isRef()) {
       delete thisOptionalContentGroup;
       break;
     }
     // TODO: we should create a lookup map from Ref to the OptionalContentGroup
     thisOptionalContentGroup->setRef( ocg.getRef() );
-    ocg.free();
     // the default is ON - we change state later, depending on BaseState, ON and OFF
     thisOptionalContentGroup->setState(OptionalContentGroup::On);
     optionalContentGroups->append(thisOptionalContentGroup);
   }
 
-  Object defaultOcgConfig;
-  ocgObject->dictLookup("D", &defaultOcgConfig);
+  Object defaultOcgConfig = ocgObject->dictLookup("D");
   if (!defaultOcgConfig.isDict()) {
     error(errSyntaxError, -1, "Expected the default config, but wasn't able to find it, or it isn't a Dictionary");
-    defaultOcgConfig.free();
-    ocgList.free();
     ok = gFalse;
     return;
   }
 
-  Object baseState;
-  defaultOcgConfig.dictLookup("BaseState", &baseState);
+  Object baseState = defaultOcgConfig.dictLookup("BaseState");
   if (baseState.isName("OFF")) {
     for (int i = 0; i < optionalContentGroups->getLength(); ++i) {
       OptionalContentGroup *group;
@@ -95,22 +85,17 @@ OCGs::OCGs(Object *ocgObject, XRef *xref) :
       group->setState(OptionalContentGroup::Off);
     }
   }
-  baseState.free();
 
-  Object on;
-  defaultOcgConfig.dictLookup("ON", &on);
+  Object on = defaultOcgConfig.dictLookup("ON");
   if (on.isArray()) {
     // ON is an optional element
     for (int i = 0; i < on.arrayGetLength(); ++i) {
-      Object reference;
-      on.arrayGetNF(i, &reference);
+      Object reference = on.arrayGetNF(i);
       if (!reference.isRef()) {
 	// there can be null entries
-	reference.free();
 	break;
       }
       OptionalContentGroup *group = findOcgByRef( reference.getRef() );
-      reference.free();
       if (!group) {
 	error(errSyntaxWarning, -1, "Couldn't find group for reference");
 	break;
@@ -118,22 +103,17 @@ OCGs::OCGs(Object *ocgObject, XRef *xref) :
       group->setState(OptionalContentGroup::On);
     }
   }
-  on.free();
 
-  Object off;
-  defaultOcgConfig.dictLookup("OFF", &off);
+  Object off = defaultOcgConfig.dictLookup("OFF");
   if (off.isArray()) {
     // OFF is an optional element
     for (int i = 0; i < off.arrayGetLength(); ++i) {
-      Object reference;
-      off.arrayGetNF(i, &reference);
+      Object reference = off.arrayGetNF(i);
       if (!reference.isRef()) {
 	// there can be null entries
-	reference.free();
 	break;
       }
       OptionalContentGroup *group = findOcgByRef( reference.getRef() );
-      reference.free();
       if (!group) {
 	error(errSyntaxWarning, -1, "Couldn't find group for reference to set OFF");
 	break;
@@ -141,22 +121,15 @@ OCGs::OCGs(Object *ocgObject, XRef *xref) :
       group->setState(OptionalContentGroup::Off);
     }
   }
-  off.free();
 
-  defaultOcgConfig.dictLookup("Order", &order);
-  defaultOcgConfig.dictLookup("RBGroups", &rbgroups);
-
-  ocgList.free();
-  defaultOcgConfig.free();
+  order = defaultOcgConfig.dictLookup("Order");
+  rbgroups = defaultOcgConfig.dictLookup("RBGroups");
 }
 
 OCGs::~OCGs()
 {
   deleteGooList(optionalContentGroups, OptionalContentGroup);
-  order.free();
-  if (display)
-    delete display;
-  rbgroups.free();
+  delete display;
 }
 
 
@@ -193,12 +166,7 @@ OCDisplayNode *OCGs::getDisplayRoot()
 
 bool OCGs::optContentIsVisible( Object *dictRef )
 {
-  Object dictObj;
   Dict *dict;
-  Object dictType;
-  Object ocg;
-  Object policy;
-  Object ve;
   bool result = true;
 
   if (dictRef->isNull())
@@ -210,22 +178,22 @@ bool OCGs::optContentIsVisible( Object *dictRef )
       return oc->getState() == OptionalContentGroup::On;
   }
 
-  dictRef->fetch( m_xref, &dictObj );
+  Object dictObj = dictRef->fetch( m_xref);
   if ( ! dictObj.isDict() ) {
     error(errSyntaxWarning, -1, "Unexpected oc reference target: {0:d}", dictObj.getType() );
-    dictObj.free();
     return result;
   }
   dict = dictObj.getDict();
   // printf("checking if optContent is visible\n");
-  dict->lookup("Type", &dictType);
+  Object dictType = dict->lookup("Type");
   if (dictType.isName("OCMD")) {
-    if (dict->lookup("VE", &ve)->isArray()) {
+    Object ve = dict->lookup("VE");
+    if (ve.isArray()) {
       result = evalOCVisibilityExpr(&ve, 0);
     } else {
-      dict->lookupNF("OCGs", &ocg);
+      Object ocg = dict->lookupNF("OCGs");
       if (ocg.isArray()) {
-        dict->lookup("P", &policy);
+        Object policy = dict->lookup("P");
         if (policy.isName("AllOn")) {
           result = allOn( ocg.getArray() );
         } else if (policy.isName("AllOff")) {
@@ -236,7 +204,6 @@ bool OCGs::optContentIsVisible( Object *dictRef )
           // this is the default
           result = anyOn( ocg.getArray() );
         }
-        policy.free();
       } else if (ocg.isRef()) {
         OptionalContentGroup *oc = findOcgByRef( ocg.getRef() );
         if ( oc && oc->getState() == OptionalContentGroup::Off ) {
@@ -245,26 +212,20 @@ bool OCGs::optContentIsVisible( Object *dictRef )
           result = true ;
         }
       }
-      ocg.free();
     }
-    ve.free();
   } else if ( dictType.isName("OCG") ) {
     OptionalContentGroup* oc = findOcgByRef( dictRef->getRef() );
     if ( oc && oc->getState() == OptionalContentGroup::Off ) {
       result=false;
     }
   }
-  dictType.free();
-  dictObj.free();
   // printf("visibility: %s\n", result? "on" : "off");
   return result;
 }
 
 GBool OCGs::evalOCVisibilityExpr(Object *expr, int recursion) {
   OptionalContentGroup *ocg;
-  Object expr2, op, obj;
   GBool ret;
-  int i;
 
   if (recursion > visibilityExprRecursionLimit) {
     error(errSyntaxError, -1,
@@ -276,19 +237,17 @@ GBool OCGs::evalOCVisibilityExpr(Object *expr, int recursion) {
       return ocg->getState() == OptionalContentGroup::On;
     }
   }
-  expr->fetch(m_xref, &expr2);
+  Object expr2 = expr->fetch(m_xref);
   if (!expr2.isArray() || expr2.arrayGetLength() < 1) {
     error(errSyntaxError, -1,
 	  "Invalid optional content visibility expression");
-    expr2.free();
     return gTrue;
   }
-  expr2.arrayGet(0, &op);
+  Object op = expr2.arrayGet(0);
   if (op.isName("Not")) {
     if (expr2.arrayGetLength() == 2) {
-      expr2.arrayGetNF(1, &obj);
+      Object obj = expr2.arrayGetNF(1);
       ret = !evalOCVisibilityExpr(&obj, recursion + 1);
-      obj.free();
     } else {
       error(errSyntaxError, -1,
 	    "Invalid optional content visibility expression");
@@ -296,33 +255,28 @@ GBool OCGs::evalOCVisibilityExpr(Object *expr, int recursion) {
     }
   } else if (op.isName("And")) {
     ret = gTrue;
-    for (i = 1; i < expr2.arrayGetLength() && ret; ++i) {
-      expr2.arrayGetNF(i, &obj);
+    for (int i = 1; i < expr2.arrayGetLength() && ret; ++i) {
+      Object obj = expr2.arrayGetNF(i);
       ret = evalOCVisibilityExpr(&obj, recursion + 1);
-      obj.free();
     }
   } else if (op.isName("Or")) {
     ret = gFalse;
-    for (i = 1; i < expr2.arrayGetLength() && !ret; ++i) {
-      expr2.arrayGetNF(i, &obj);
+    for (int i = 1; i < expr2.arrayGetLength() && !ret; ++i) {
+      Object obj = expr2.arrayGetNF(i);
       ret = evalOCVisibilityExpr(&obj, recursion + 1);
-      obj.free();
     }
   } else {
     error(errSyntaxError, -1,
 	  "Invalid optional content visibility expression");
     ret = gTrue;
   }
-  op.free();
-  expr2.free();
   return ret;
 }
 
 bool OCGs::allOn( Array *ocgArray )
 {
   for (int i = 0; i < ocgArray->getLength(); ++i) {
-    Object ocgItem;
-    ocgArray->getNF(i, &ocgItem);
+    Object ocgItem = ocgArray->getNF(i);
     if (ocgItem.isRef()) {
       OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );      
       if ( oc && oc->getState() == OptionalContentGroup::Off ) {
@@ -336,8 +290,7 @@ bool OCGs::allOn( Array *ocgArray )
 bool OCGs::allOff( Array *ocgArray )
 {
   for (int i = 0; i < ocgArray->getLength(); ++i) {
-    Object ocgItem;
-    ocgArray->getNF(i, &ocgItem);
+    Object ocgItem = ocgArray->getNF(i);
     if (ocgItem.isRef()) {
       OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );      
       if ( oc && oc->getState() == OptionalContentGroup::On ) {
@@ -351,8 +304,7 @@ bool OCGs::allOff( Array *ocgArray )
 bool OCGs::anyOn( Array *ocgArray )
 {
   for (int i = 0; i < ocgArray->getLength(); ++i) {
-    Object ocgItem;
-    ocgArray->getNF(i, &ocgItem);
+    Object ocgItem = ocgArray->getNF(i);
     if (ocgItem.isRef()) {
       OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );      
       if ( oc && oc->getState() == OptionalContentGroup::On ) {
@@ -366,8 +318,7 @@ bool OCGs::anyOn( Array *ocgArray )
 bool OCGs::anyOff( Array *ocgArray )
 {
   for (int i = 0; i < ocgArray->getLength(); ++i) {
-    Object ocgItem;
-    ocgArray->getNF(i, &ocgItem);
+    Object ocgItem = ocgArray->getNF(i);
     if (ocgItem.isRef()) {
       OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );      
       if ( oc && oc->getState() == OptionalContentGroup::Off ) {
@@ -382,42 +333,39 @@ bool OCGs::anyOff( Array *ocgArray )
 
 OptionalContentGroup::OptionalContentGroup(Dict *ocgDict) : m_name(NULL)
 {
-  Object obj1, obj2, obj3;
-  Object ocgName;
-  ocgDict->lookup("Name", &ocgName);
+  Object ocgName = ocgDict->lookup("Name");
   if (!ocgName.isString()) {
     error(errSyntaxWarning, -1, "Expected the name of the OCG, but wasn't able to find it, or it isn't a String");
   } else {
     m_name = new GooString( ocgName.getString() );
   }
-  ocgName.free();
 
   viewState = printState = ocUsageUnset;
-  if (ocgDict->lookup("Usage", &obj1)->isDict()) {
-    if (obj1.dictLookup("View", &obj2)->isDict()) {
-      if (obj2.dictLookup("ViewState", &obj3)->isName()) {
+  Object obj1 = ocgDict->lookup("Usage");
+  if (obj1.isDict()) {
+    Object obj2 = obj1.dictLookup("View");
+    if (obj2.isDict()) {
+      Object obj3 = obj2.dictLookup("ViewState");
+      if (obj3.isName()) {
 	if (obj3.isName("ON")) {
 	  viewState = ocUsageOn;
 	} else {
 	  viewState = ocUsageOff;
 	}
       }
-      obj3.free();
     }
-    obj2.free();
-    if (obj1.dictLookup("Print", &obj2)->isDict()) {
-      if (obj2.dictLookup("PrintState", &obj3)->isName()) {
+    obj2 = obj1.dictLookup("Print");
+    if (obj2.isDict()) {
+      Object obj3 = obj2.dictLookup("PrintState");
+      if (obj3.isName()) {
 	if (obj3.isName("ON")) {
 	  printState = ocUsageOn;
 	} else {
 	  printState = ocUsageOff;
 	}
       }
-      obj3.free();
     }
-    obj2.free();
   }
-  obj1.free();
 }
 
 OptionalContentGroup::OptionalContentGroup(GooString *label)
@@ -450,7 +398,6 @@ OptionalContentGroup::~OptionalContentGroup()
 
 OCDisplayNode *OCDisplayNode::parse(Object *obj, OCGs *oc,
 				    XRef *xref, int recursion) {
-  Object obj2, obj3;
   OptionalContentGroup *ocgA;
   OCDisplayNode *node, *child;
   int i;
@@ -464,25 +411,24 @@ OCDisplayNode *OCDisplayNode::parse(Object *obj, OCGs *oc,
       return new OCDisplayNode(ocgA);
     }
   }
-  obj->fetch(xref, &obj2);
+  Object obj2 = obj->fetch(xref);
   if (!obj2.isArray()) {
-    obj2.free();
     return NULL;
   }
   i = 0;
   if (obj2.arrayGetLength() >= 1) {
-    if (obj2.arrayGet(0, &obj3)->isString()) {
+    Object obj3 = obj2.arrayGet(0);
+    if (obj3.isString()) {
       node = new OCDisplayNode(obj3.getString());
       i = 1;
     } else {
       node = new OCDisplayNode();
     }
-    obj3.free();
   } else {
     node = new OCDisplayNode();
   }
   for (; i < obj2.arrayGetLength(); ++i) {
-    obj2.arrayGetNF(i, &obj3);
+    Object obj3 = obj2.arrayGetNF(i);
     if ((child = OCDisplayNode::parse(&obj3, oc, xref, recursion + 1))) {
       if (!child->ocg && !child->name && node->getNumChildren() > 0) {
 	node->getChild(node->getNumChildren() - 1)->addChildren(child->takeChildren());
@@ -491,9 +437,7 @@ OCDisplayNode *OCDisplayNode::parse(Object *obj, OCGs *oc,
 	node->addChild(child);
       }
     }
-    obj3.free();
   }
-  obj2.free();
   return node;
 }
 
diff --git a/poppler/Outline.cc b/poppler/Outline.cc
index bf46be26..f3380211 100644
--- a/poppler/Outline.cc
+++ b/poppler/Outline.cc
@@ -41,15 +41,12 @@
 //------------------------------------------------------------------------
 
 Outline::Outline(Object *outlineObj, XRef *xref) {
-  Object first, last;
-
-  items = NULL;
+  items = nullptr;
   if (!outlineObj->isDict()) {
     return;
   }
-  items = OutlineItem::readItemList(outlineObj->dictLookupNF("First", &first), xref);
-  first.free();
-  last.free();
+  Object first = outlineObj->dictLookupNF("First");
+  items = OutlineItem::readItemList(&first, xref);
 }
 
 Outline::~Outline() {
@@ -62,42 +59,41 @@ Outline::~Outline() {
 
 OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) {
   Object obj1;
-  GooString *s;
 
   xref = xrefA;
   title = NULL;
   action = NULL;
   kids = NULL;
 
-  if (dict->lookup("Title", &obj1)->isString()) {
-    s = obj1.getString();
+
+  if (obj1.isString()) {
+    GooString *s = obj1.getString();
     titleLen = TextStringToUCS4(s, &title);
   } else {
     titleLen = 0;
   }
-  obj1.free();
 
-  if (!dict->lookup("Dest", &obj1)->isNull()) {
+  obj1 = dict->lookup("Dest");
+  if (!obj1.isNull()) {
     action = LinkAction::parseDest(&obj1);
   } else {
-      obj1.free();
-    if (!dict->lookup("A", &obj1)->isNull()) {
-        action = LinkAction::parseAction(&obj1);
-  }
+    obj1 = dict->lookup("A");
+    if (!obj1.isNull()) {
+      action = LinkAction::parseAction(&obj1);
+    }
   }
-  obj1.free();
 
-  dict->lookupNF("First", &firstRef);
-  dict->lookupNF("Last", &lastRef);
-  dict->lookupNF("Next", &nextRef);
+  firstRef = dict->lookupNF("First");
+  lastRef = dict->lookupNF("Last");
+  nextRef = dict->lookupNF("Next");
 
   startsOpen = gFalse;
-  if (dict->lookup("Count", &obj1)->isInt()) {
+  obj1 = dict->lookup("Count");
+  if (obj1.isInt()) {
     if (obj1.getInt() > 0) {
       startsOpen = gTrue;
     }
   }
-  obj1.free();
 }
 
 OutlineItem::~OutlineItem() {
@@ -108,16 +104,12 @@ OutlineItem::~OutlineItem() {
   if (action) {
     delete action;
   }
-  firstRef.free();
-  lastRef.free();
-  nextRef.free();
 }
 
 GooList *OutlineItem::readItemList(Object *firstItemRef, XRef *xrefA) {
   GooList *items;
   char* alreadyRead;
   OutlineItem *item;
-  Object obj;
   Object *p;
 
   items = new GooList();
@@ -130,13 +122,12 @@ GooList *OutlineItem::readItemList(Object *firstItemRef, XRef *xrefA) {
 	 (p->getRefNum() >= 0) && 
          (p->getRefNum() < xrefA->getNumObjects()) && 
          !alreadyRead[p->getRefNum()]) {
-    if (!p->fetch(xrefA, &obj)->isDict()) {
-      obj.free();
+    Object obj = p->fetch(xrefA);
+    if (!obj.isDict()) {
       break;
     }
     alreadyRead[p->getRefNum()] = 1;
     item = new OutlineItem(obj.getDict(), xrefA);
-    obj.free();
     items->append(item);
     p = &item->nextRef;
   }
diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index f02f192f..5f640790 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -132,7 +132,6 @@ PDFDoc::PDFDoc()
 
 PDFDoc::PDFDoc(GooString *fileNameA, GooString *ownerPassword,
 	       GooString *userPassword, void *guiDataA) {
-  Object obj;
 #ifdef _WIN32
   int n, i;
 #endif
@@ -163,8 +162,7 @@ PDFDoc::PDFDoc(GooString *fileNameA, GooString *ownerPassword,
   }
 
   // create stream
-  obj.initNull();
-  str = new FileStream(file, 0, gFalse, file->size(), &obj);
+  str = new FileStream(file, 0, gFalse, file->size(), Object(objNull));
 
   ok = setup(ownerPassword, userPassword);
 }
@@ -419,11 +417,10 @@ void PDFDoc::checkHeader() {
 }
 
 GBool PDFDoc::checkEncryption(GooString *ownerPassword, GooString *userPassword) {
-  Object encrypt;
   GBool encrypted;
   GBool ret;
 
-  xref->getTrailerDict()->dictLookup("Encrypt", &encrypt);
+  Object encrypt = xref->getTrailerDict()->dictLookup("Encrypt");
   if ((encrypted = encrypt.isDict())) {
     if ((secHdlr = SecurityHandler::make(this, &encrypt))) {
       if (secHdlr->isUnencrypted()) {
@@ -451,7 +448,6 @@ GBool PDFDoc::checkEncryption(GooString *ownerPassword, GooString *userPassword)
     // document is not encrypted
     ret = gTrue;
   }
-  encrypt.free();
   return ret;
 }
 
@@ -565,7 +561,6 @@ GBool PDFDoc::checkLinearization() {
     return gFalse;
   }
   for (int page = 1; page <= linearization->getNumPages(); page++) {
-    Object obj;
     Ref pageRef;
 
     pageRef.num = hints->getPageObjectNum(page);
@@ -581,13 +576,11 @@ GBool PDFDoc::checkLinearization() {
     }
 
     pageRef.gen = xref->getEntry(pageRef.num)->gen;
-    xref->fetch(pageRef.num, pageRef.gen, &obj);
+    Object obj = xref->fetch(pageRef.num, pageRef.gen);
     if (!obj.isDict("Page")) {
-      obj.free();
       linearizationState = 2;
       return gFalse;
     }
-    obj.free();
   }
   linearizationState = 1;
   return gTrue;
@@ -607,10 +600,8 @@ GBool PDFDoc::isLinearized(GBool tryingToReconstruct) {
 
 void PDFDoc::setDocInfoModified(Object *infoObj)
 {
-  Object infoObjRef;
-  getDocInfoNF(&infoObjRef);
+  Object infoObjRef = getDocInfoNF();
   xref->setModifiedObject(infoObj, infoObjRef.getRef());
-  infoObjRef.free();
 }
 
 void PDFDoc::setDocInfoStringEntry(const char *key, GooString *value)
@@ -620,25 +611,19 @@ void PDFDoc::setDocInfoStringEntry(const char *key, GooString *value)
     delete value;
   }
 
-  Object infoObj;
-  getDocInfo(&infoObj);
-
+  Object infoObj = getDocInfo();
   if (infoObj.isNull() && removeEntry) {
     // No info dictionary, so no entry to remove.
     return;
   }
 
-  createDocInfoIfNoneExists(&infoObj);
-
-  Object gooStrObj;
+  infoObj = createDocInfoIfNoneExists();
   if (removeEntry) {
-    gooStrObj.initNull();
+    infoObj.dictSet(key, Object(objNull));
   } else {
-    gooStrObj.initString(value);
+    infoObj.dictSet(key, Object(value));
   }
 
-  // gooStrObj is set to value or null by now. The latter will cause a removal.
-  infoObj.dictSet(key, &gooStrObj);
 
   if (infoObj.dictGetLength() == 0) {
     // Info dictionary is empty. Remove it altogether.
@@ -646,19 +631,15 @@ void PDFDoc::setDocInfoStringEntry(const char *key, GooString *value)
   } else {
     setDocInfoModified(&infoObj);
   }
-
-  infoObj.free();
 }
 
 GooString *PDFDoc::getDocInfoStringEntry(const char *key) {
-  Object infoObj;
-  getDocInfo(&infoObj);
+  Object infoObj = getDocInfo();
   if (!infoObj.isDict()) {
       return NULL;
   }
 
-  Object entryObj;
-  infoObj.dictLookup(key, &entryObj);
+  Object entryObj = infoObj.dictLookup(key);
 
   GooString *result;
 
@@ -668,9 +649,6 @@ GooString *PDFDoc::getDocInfoStringEntry(const char *key) {
     result = NULL;
   }
 
-  entryObj.free();
-  infoObj.free();
-
   return result;
 }
 
@@ -696,45 +674,35 @@ get_id (GooString *encodedidstring, GooString *id) {
 }
 
 GBool PDFDoc::getID(GooString *permanent_id, GooString *update_id) {
-  Object obj;
-  xref->getTrailerDict()->dictLookup ("ID", &obj);
+  Object obj = xref->getTrailerDict()->dictLookup ("ID");
 
   if (obj.isArray() && obj.arrayGetLength() == 2) {
-    Object obj2;
-
     if (permanent_id) {
-      if (obj.arrayGet(0, &obj2)->isString()) {
+      Object obj2 = obj.arrayGet(0);
+      if (obj2.isString()) {
         if (!get_id (obj2.getString(), permanent_id)) {
-	  obj2.free();
 	  return gFalse;
 	}
       } else {
         error(errSyntaxError, -1, "Invalid permanent ID");
-	obj2.free();
 	return gFalse;
       }
-      obj2.free();
     }
 
     if (update_id) {
-      if (obj.arrayGet(1, &obj2)->isString()) {
+      Object obj2 = obj.arrayGet(1);
+      if (obj2.isString()) {
         if (!get_id (obj2.getString(), update_id)) {
-	  obj2.free();
 	  return gFalse;
 	}
       } else {
         error(errSyntaxError, -1, "Invalid update ID");
-	obj2.free();
 	return gFalse;
       }
-      obj2.free();
     }
 
-    obj.free();
-
     return gTrue;
   }
-  obj.free();
 
   return gFalse;
 }
@@ -777,8 +745,7 @@ int PDFDoc::savePageAs(GooString *name, int pageNo)
     getCatalog()->getPage(pageNo)->getMediaBox(),
     cropBox);
   Ref *refPage = getCatalog()->getPageRef(pageNo);
-  Object page;
-  getXRef()->fetch(refPage->num, refPage->gen, &page);
+  Object page = getXRef()->fetch(refPage->num, refPage->gen);
 
   if (!(f = fopen(name->getCString(), "wb"))) {
     error(errIO, -1, "Couldn't open file '{0:t}'", name);
@@ -801,55 +768,48 @@ int PDFDoc::savePageAs(GooString *name, int pageNo)
   writeHeader(outStr, getPDFMajorVersion(), getPDFMinorVersion());
 
   // get and mark info dict
-  Object infoObj;
-  getXRef()->getDocInfo(&infoObj);
+  Object infoObj = getXRef()->getDocInfo();
   if (infoObj.isDict()) {
     Dict *infoDict = infoObj.getDict();
     markPageObjects(infoDict, yRef, countRef, 0, refPage->num, rootNum + 2);
     if (trailerObj->isDict()) {
       Dict *trailerDict = trailerObj->getDict();
-      Object ref;
-      trailerDict->lookupNF("Info", &ref);
+      Object ref = trailerDict->lookupNF("Info");
       if (ref.isRef()) {
         yRef->add(ref.getRef().num, ref.getRef().gen, 0, gTrue);
         if (getXRef()->getEntry(ref.getRef().num)->type == xrefEntryCompressed) {
           yRef->getEntry(ref.getRef().num)->type = xrefEntryCompressed;
         }
       }
-      ref.free();
     }
   }
-  infoObj.free();
   
   // get and mark output intents etc.
-  Object catObj, pagesObj, resourcesObj, annotsObj, afObj;
-  getXRef()->getCatalog(&catObj);
+  Object catObj = getXRef()->getCatalog();
   Dict *catDict = catObj.getDict();
-  catDict->lookup("Pages", &pagesObj);
-  catDict->lookupNF("AcroForm", &afObj);
+  Object pagesObj = catDict->lookup("Pages");
+  Object afObj = catDict->lookupNF("AcroForm");
   if (!afObj.isNull()) {
     markAcroForm(&afObj, yRef, countRef, 0, refPage->num, rootNum + 2);
-    afObj.free();
   }
   Dict *pagesDict = pagesObj.getDict();
-  pagesDict->lookup("Resources", &resourcesObj);
+  Object resourcesObj = pagesDict->lookup("Resources");
   if (resourcesObj.isDict())
     markPageObjects(resourcesObj.getDict(), yRef, countRef, 0, refPage->num, rootNum + 2);
   markPageObjects(catDict, yRef, countRef, 0, refPage->num, rootNum + 2);
 
   Dict *pageDict = page.getDict();
   if (resourcesObj.isNull() && !pageDict->hasKey("Resources")) {
-    Dict *resourceDict = getCatalog()->getPage(pageNo)->getResourceDict();
-    if (resourceDict != NULL) {
-      resourcesObj.initDict(resourceDict);
+    Object *resourceDictObject = getCatalog()->getPage(pageNo)->getResourceDictObject();
+    if (resourceDictObject->isDict()) {
+      resourcesObj = resourceDictObject->copy();
       markPageObjects(resourcesObj.getDict(), yRef, countRef, 0, refPage->num, rootNum + 2);
     }
   }
   markPageObjects(pageDict, yRef, countRef, 0, refPage->num, rootNum + 2);
-  pageDict->lookupNF("Annots", &annotsObj);
+  Object annotsObj = pageDict->lookupNF("Annots");
   if (!annotsObj.isNull()) {
     markAnnotations(&annotsObj, yRef, countRef, 0, refPage->num, rootNum + 2);
-    annotsObj.free();
   }
   yRef->markUnencrypted();
   writePageObjects(outStr, yRef, 0);
@@ -864,14 +824,11 @@ int PDFDoc::savePageAs(GooString *name, int pageNo)
       strcmp(key, "Pages") != 0) 
     {
       if (j > 0) outStr->printf(" ");
-      Object value; catDict->getValNF(j, &value);
+      Object value = catDict->getValNF(j);
       outStr->printf("/%s ", key);
       writeObject(&value, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0);
-      value.free();
     }
   }
-  catObj.free();
-  pagesObj.free();
   outStr->printf(">>\nendobj\n");
 
   yRef->add(rootNum + 1,0,outStr->getPos(),gTrue);
@@ -880,7 +837,6 @@ int PDFDoc::savePageAs(GooString *name, int pageNo)
   if (resourcesObj.isDict()) {
     outStr->printf("/Resources ");
     writeObject(&resourcesObj, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0);
-    resourcesObj.free();
   }
   outStr->printf(">>\n");
   outStr->printf("endobj\n");
@@ -891,17 +847,15 @@ int PDFDoc::savePageAs(GooString *name, int pageNo)
   for (int n = 0; n < pageDict->getLength(); n++) {
     if (n > 0) outStr->printf(" ");
     const char *key = pageDict->getKey(n);
-    Object value; pageDict->getValNF(n, &value);
+    Object value = pageDict->getValNF(n);
     if (strcmp(key, "Parent") == 0) {
       outStr->printf("/Parent %d 0 R", rootNum + 1);
     } else {
       outStr->printf("/%s ", key);
       writeObject(&value, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0);
     }
-    value.free();
   }
   outStr->printf(" >>\nendobj\n");
-  page.free();
 
   Goffset uxrefOffset = outStr->getPos();
   Ref ref;
@@ -1015,13 +969,11 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr)
       ref.num = i;
       ref.gen = xref->getEntry(i)->type == xrefEntryCompressed ? 0 : xref->getEntry(i)->gen;
       if (xref->getEntry(i)->type != xrefEntryFree) {
-        Object obj1;
-        xref->fetch(ref.num, ref.gen, &obj1, 1);
+        Object obj1 = xref->fetch(ref.num, ref.gen, 1);
         Goffset offset = writeObjectHeader(&ref, outStr);
         writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen);
         writeObjectFooter(outStr);
         uxref->add(ref.num, ref.gen, offset, gTrue);
-        obj1.free();
       } else {
         uxref->add(ref.num, ref.gen, 0, gFalse);
       }
@@ -1079,7 +1031,6 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr)
   uxref->add(0, 65535, 0, gFalse);
   xref->lock();
   for(int i=0; i<xref->getNumObjects(); i++) {
-    Object obj1;
     Ref ref;
     XRefEntryType type = xref->getEntry(i)->type;
     if (type == xrefEntryFree) {
@@ -1097,7 +1048,7 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr)
     } else if (type == xrefEntryUncompressed){ 
       ref.num = i;
       ref.gen = xref->getEntry(i)->gen;
-      xref->fetch(ref.num, ref.gen, &obj1, 1);
+      Object obj1 = xref->fetch(ref.num, ref.gen, 1);
       Goffset offset = writeObjectHeader(&ref, outStr);
       // Write unencrypted objects in unencrypted form
       if (xref->getEntry(i)->getFlag(XRefEntry::Unencrypted)) {
@@ -1107,16 +1058,14 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr)
       }
       writeObjectFooter(outStr);
       uxref->add(ref.num, ref.gen, offset, gTrue);
-      obj1.free();
     } else if (type == xrefEntryCompressed) {
       ref.num = i;
       ref.gen = 0; //compressed entries have gen == 0
-      xref->fetch(ref.num, ref.gen, &obj1, 1);
+      Object obj1 = xref->fetch(ref.num, ref.gen, 1);
       Goffset offset = writeObjectHeader(&ref, outStr);
       writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen);
       writeObjectFooter(outStr);
       uxref->add(ref.num, ref.gen, offset, gTrue);
-      obj1.free();
     }
   }
   xref->unlock();
@@ -1129,15 +1078,14 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr)
 void PDFDoc::writeDictionnary (Dict* dict, OutStream* outStr, XRef *xRef, Guint numOffset, Guchar *fileKey,
                                CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen)
 {
-  Object obj1;
   outStr->printf("<<");
   for (int i=0; i<dict->getLength(); i++) {
     GooString keyName(dict->getKey(i));
     GooString *keyNameToPrint = keyName.sanitizedName(gFalse /* non ps mode */);
     outStr->printf("/%s ", keyNameToPrint->getCString());
     delete keyNameToPrint;
-    writeObject(dict->getValNF(i, &obj1), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
-    obj1.free();
+    Object obj1 = dict->getValNF(i);
+    writeObject(&obj1, outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
   }
   outStr->printf(">> ");
 }
@@ -1154,8 +1102,7 @@ void PDFDoc::writeStream (Stream* str, OutStream* outStr)
 
 void PDFDoc::writeRawStream (Stream* str, OutStream* outStr)
 {
-  Object obj1;
-  str->getDict()->lookup("Length", &obj1);
+  Object obj1 = str->getDict()->lookup("Length");
   if (!obj1.isInt() && !obj1.isInt64()) {
     error (errSyntaxError, -1, "PDFDoc::writeRawStream, no Length in stream dict");
     return;
@@ -1166,7 +1113,6 @@ void PDFDoc::writeRawStream (Stream* str, OutStream* outStr)
     length = obj1.getInt();
   else
     length = obj1.getInt64();
-  obj1.free();
 
   outStr->printf("stream\r\n");
   str->unfilteredReset();
@@ -1188,8 +1134,7 @@ void PDFDoc::writeString (GooString* s, OutStream* outStr, Guchar *fileKey,
   // Encrypt string if encryption is enabled
   GooString *sEnc = NULL;
   if (fileKey) {
-    Object obj;
-    EncryptStream *enc = new EncryptStream(new MemStream(s->getCString(), 0, s->getLength(), obj.initNull()),
+    EncryptStream *enc = new EncryptStream(new MemStream(s->getCString(), 0, s->getLength(), Object(objNull)),
                                            fileKey, encAlgorithm, keyLength, objNum, objGen);
     sEnc = new GooString();
     int c;
@@ -1249,8 +1194,6 @@ void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numO
                           CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen)
 {
   Array *array;
-  Object obj1;
-  Goffset tmp;
 
   switch (obj->getType()) {
     case objBool:
@@ -1287,8 +1230,8 @@ void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numO
       array = obj->getArray();
       outStr->printf("[");
       for (int i=0; i<array->getLength(); i++) {
-        writeObject(array->getNF(i, &obj1), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
-        obj1.free();
+	Object obj1 = array->getNF(i);
+        writeObject(&obj1, outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
       }
       outStr->printf("] ");
       break;
@@ -1307,19 +1250,15 @@ void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numO
           EncryptStream *encStream = NULL;
           GBool removeFilter = gTrue;
           if (stream->getKind() == strWeird && fileKey) {
-            Object filter;
-            stream->getDict()->lookup("Filter", &filter);
+            Object filter = stream->getDict()->lookup("Filter");
             if (!filter.isName("Crypt")) {
               if (filter.isArray()) {
                 for (int i = 0; i < filter.arrayGetLength(); i++) {
-                  Object filterEle;
-                  filter.arrayGet(i, &filterEle);
+                  Object filterEle = filter.arrayGet(i);
                   if (filterEle.isName("Crypt")) {
-                    filterEle.free();
                     removeFilter = gFalse;
                     break;
                   }
-                  filterEle.free();
                 }
                 if (removeFilter) {
                   encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, objNum, objGen);
@@ -1334,7 +1273,6 @@ void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numO
             } else {
               removeFilter = gFalse;
             }
-            filter.free();
           } else if (fileKey != NULL) { // Encrypt stream
             encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, objNum, objGen);
             encStream->setAutoDelete(gFalse);
@@ -1343,12 +1281,11 @@ void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numO
 
           stream->reset();
           //recalculate stream length
-          tmp = 0;
+          Goffset tmp = 0;
           for (int c=stream->getChar(); c!=EOF; c=stream->getChar()) {
             tmp++;
           }
-          obj1.initInt64(tmp);
-          stream->getDict()->set("Length", &obj1);
+          stream->getDict()->set("Length", Object(tmp));
 
           //Remove Stream encoding
           if (removeFilter) {
@@ -1359,7 +1296,6 @@ void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numO
           writeDictionnary (stream->getDict(),outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
           writeStream (stream,outStr);
           delete encStream;
-          obj1.free();
         } else {
           //raw stream copy
           FilterStream *fs = dynamic_cast<FilterStream*>(stream);
@@ -1368,9 +1304,8 @@ void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numO
             if (bs) {
               Goffset streamEnd;
                 if (xRef->getStreamEnd(bs->getStart(), &streamEnd)) {
-                  Object val;
-                  val.initInt64(streamEnd - bs->getStart());
-                  stream->getDict()->set("Length", &val);
+                  Goffset val = streamEnd - bs->getStart();
+                  stream->getDict()->set("Length", Object(val));
                 }
               }
           }
@@ -1409,10 +1344,7 @@ Dict *PDFDoc::createTrailerDict(int uxrefSize, GBool incrUpdate, Goffset startxR
                                 Ref *root, XRef *xRef, const char *fileName, Goffset fileSize)
 {
   Dict *trailerDict = new Dict(xRef);
-  Object obj1;
-  obj1.initInt(uxrefSize);
-  trailerDict->set("Size", &obj1);
-  obj1.free();
+  trailerDict->set("Size", Object(uxrefSize));
 
   //build a new ID, as recommended in the reference, uses:
   // - current time
@@ -1431,74 +1363,61 @@ Dict *PDFDoc::createTrailerDict(int uxrefSize, GBool incrUpdate, Goffset startxR
   message.append(buffer);
 
   //info dict -- only use text string
-  if (!xRef->getTrailerDict()->isNone() && xRef->getDocInfo(&obj1)->isDict()) {
-    for(int i=0; i<obj1.getDict()->getLength(); i++) {
-      Object obj2;
-      obj1.getDict()->getVal(i, &obj2);  
+  Object docInfo = xRef->getDocInfo();
+  if (!xRef->getTrailerDict()->isNone() && docInfo.isDict()) {
+    for(int i=0; i<docInfo.getDict()->getLength(); i++) {
+      Object obj2 = docInfo.getDict()->getVal(i);
       if (obj2.isString()) {
         message.append(obj2.getString());
       }
-      obj2.free();
     }
   }
-  obj1.free();
 
   GBool hasEncrypt = gFalse;
   if (!xRef->getTrailerDict()->isNone()) {
-    Object obj2;
-    xRef->getTrailerDict()->dictLookupNF("Encrypt", &obj2);
+    Object obj2 = xRef->getTrailerDict()->dictLookupNF("Encrypt");
     if (!obj2.isNull()) {
-      trailerDict->set("Encrypt", &obj2);
+      trailerDict->set("Encrypt", std::move(obj2));
       hasEncrypt = gTrue;
-      obj2.free();
     }
   }
 
   //calculate md5 digest
   Guchar digest[16];
   md5((Guchar*)message.getCString(), message.getLength(), digest);
-  obj1.initString(new GooString((const char*)digest, 16));
 
   //create ID array
-  Object obj2,obj3,obj5;
-  obj2.initArray(xRef);
-
   // In case of encrypted files, the ID must not be changed because it's used to calculate the key
   if (incrUpdate || hasEncrypt) {
-    Object obj4;
     //only update the second part of the array
-    xRef->getTrailerDict()->getDict()->lookup("ID", &obj4);
+    Object obj4  = xRef->getTrailerDict()->getDict()->lookup("ID");
     if (!obj4.isArray()) {
       error(errSyntaxWarning, -1, "PDFDoc::createTrailerDict original file's ID entry isn't an array. Trying to continue");
     } else {
+      Array *array = new Array(xRef);
       //Get the first part of the ID
-      obj4.arrayGet(0,&obj3); 
-
-      obj2.arrayAdd(&obj3); 
-      obj2.arrayAdd(&obj1);
-      trailerDict->set("ID", &obj2);
+      array->add(obj4.arrayGet(0));
+      array->add(Object(new GooString((const char*)digest, 16)));
+      trailerDict->set("ID", Object(array));
     }
-    obj4.free();
   } else {
     //new file => same values for the two identifiers
-    obj2.arrayAdd(&obj1);
-    obj1.initString(new GooString((const char*)digest, 16));
-    obj2.arrayAdd(&obj1);
-    trailerDict->set("ID", &obj2);
+    Array *array = new Array(xRef);
+    array->add(Object(new GooString((const char*)digest, 16)));
+    array->add(Object(new GooString((const char*)digest, 16)));
+    trailerDict->set("ID", Object(array));
   }
 
-  obj1.initRef(root->num, root->gen);
-  trailerDict->set("Root", &obj1);
+  trailerDict->set("Root", Object(root->num, root->gen));
 
   if (incrUpdate) { 
-    obj1.initInt64(startxRef);
-    trailerDict->set("Prev", &obj1);
+    trailerDict->set("Prev", Object(startxRef));
   }
   
   if (!xRef->getTrailerDict()->isNone()) {
-    xRef->getDocInfoNF(&obj5);
+    Object obj5 = xRef->getDocInfoNF();
     if (!obj5.isNull()) {
-      trailerDict->set("Info", &obj5);
+      trailerDict->set("Info", std::move(obj5));
     }
   }
 
@@ -1523,13 +1442,12 @@ void PDFDoc::writeXRefStreamTrailer (Dict *trailerDict, XRef *uxref, Ref *uxrefS
   uxref->writeStreamToBuffer(&stmData, trailerDict, xRef);
 
   // Create XRef stream object and write it
-  Object obj1;
-  MemStream *mStream = new MemStream( stmData.getCString(), 0,
-                                      stmData.getLength(), obj1.initDict(trailerDict) );
+  trailerDict->incRef();
+  MemStream *mStream = new MemStream( stmData.getCString(), 0, stmData.getLength(), Object(trailerDict) );
   writeObjectHeader(uxrefStreamRef, outStr);
-  writeObject(obj1.initStream(mStream), outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0);
+  Object obj1(static_cast<Stream*>(mStream));
+  writeObject(&obj1, outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0);
   writeObjectFooter(outStr);
-  obj1.free();
 
   outStr->printf( "startxref\r\n");
   outStr->printf( "%lli\r\n", uxrefOffset);
@@ -1565,34 +1483,30 @@ void PDFDoc::writeHeader(OutStream *outStr, int major, int minor)
 
 void PDFDoc::markDictionnary (Dict* dict, XRef * xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum)
 {
-  Object obj1;
   for (int i=0; i<dict->getLength(); i++) {
     const char *key = dict->getKey(i);
     if (strcmp(key, "Annots") != 0) {
-      markObject(dict->getValNF(i, &obj1), xRef, countRef, numOffset, oldRefNum, newRefNum);
+      Object obj1 = dict->getValNF(i);
+      markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum);
     } else {
-      Object annotsObj;
-      dict->getValNF(i, &annotsObj);
+      Object annotsObj = dict->getValNF(i);
       if (!annotsObj.isNull()) {
         markAnnotations(&annotsObj, xRef, countRef, 0, oldRefNum, newRefNum);
-        annotsObj.free();
       }
     }
-    obj1.free();
   }
 }
 
 void PDFDoc::markObject (Object* obj, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum)
 {
   Array *array;
-  Object obj1;
 
   switch (obj->getType()) {
     case objArray:
       array = obj->getArray();
       for (int i=0; i<array->getLength(); i++) {
-        markObject(array->getNF(i, &obj1), xRef, countRef, numOffset, oldRefNum, newRefNum);
-        obj1.free();
+        Object obj1 = array->getNF(i);
+        markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum);
       }
       break;
     case objDict:
@@ -1625,10 +1539,8 @@ void PDFDoc::markObject (Object* obj, XRef *xRef, XRef *countRef, Guint numOffse
           if (entry->gen > 9)
             break;
         } 
-        Object obj1;
-        getXRef()->fetch(obj->getRef().num, obj->getRef().gen, &obj1);
+        Object obj1 = getXRef()->fetch(obj->getRef().num, obj->getRef().gen);
         markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum);
-        obj1.free();
       }
       break;
     default:
@@ -1641,8 +1553,7 @@ void PDFDoc::replacePageDict(int pageNo, int rotate,
                              PDFRectangle *cropBox)
 {
   Ref *refPage = getCatalog()->getPageRef(pageNo);
-  Object page;
-  getXRef()->fetch(refPage->num, refPage->gen, &page);
+  Object page = getXRef()->fetch(refPage->num, refPage->gen);
   Dict *pageDict = page.getDict();
   pageDict->remove("MediaBoxssdf");
   pageDict->remove("MediaBox");
@@ -1651,48 +1562,27 @@ void PDFDoc::replacePageDict(int pageNo, int rotate,
   pageDict->remove("BleedBox");
   pageDict->remove("TrimBox");
   pageDict->remove("Rotate");
-  Object mediaBoxObj;
-  mediaBoxObj.initArray(getXRef());
-  Object murx;
-  murx.initReal(mediaBox->x1);
-  Object mury;
-  mury.initReal(mediaBox->y1);
-  Object mllx;
-  mllx.initReal(mediaBox->x2);
-  Object mlly;
-  mlly.initReal(mediaBox->y2);
-  mediaBoxObj.arrayAdd(&murx);
-  mediaBoxObj.arrayAdd(&mury);
-  mediaBoxObj.arrayAdd(&mllx);
-  mediaBoxObj.arrayAdd(&mlly);
-  pageDict->add(copyString("MediaBox"), &mediaBoxObj);
+  Array *mediaBoxArray = new Array(getXRef());
+  mediaBoxArray->add(Object(mediaBox->x1));
+  mediaBoxArray->add(Object(mediaBox->y1));
+  mediaBoxArray->add(Object(mediaBox->x2));
+  mediaBoxArray->add(Object(mediaBox->y2));
+  pageDict->add(copyString("MediaBox"), Object(mediaBoxArray));
   if (cropBox != NULL) {
-    Object cropBoxObj;
-    cropBoxObj.initArray(getXRef());
-    Object curx;
-    curx.initReal(cropBox->x1);
-    Object cury;
-    cury.initReal(cropBox->y1);
-    Object cllx;
-    cllx.initReal(cropBox->x2);
-    Object clly;
-    clly.initReal(cropBox->y2);
-    cropBoxObj.arrayAdd(&curx);
-    cropBoxObj.arrayAdd(&cury);
-    cropBoxObj.arrayAdd(&cllx);
-    cropBoxObj.arrayAdd(&clly);
-    pageDict->add(copyString("CropBox"), &cropBoxObj);
-    cropBoxObj.getArray()->incRef();
-    pageDict->add(copyString("TrimBox"), &cropBoxObj);
+    Array *cropBoxArray = new Array(getXRef());
+    cropBoxArray->add(Object(cropBox->x1));
+    cropBoxArray->add(Object(cropBox->y1));
+    cropBoxArray->add(Object(cropBox->x2));
+    cropBoxArray->add(Object(cropBox->y2));
+    pageDict->add(copyString("CropBox"), Object(cropBoxArray));
+    cropBoxArray->incRef();
+    pageDict->add(copyString("TrimBox"), Object(cropBoxArray));
   } else {
-    mediaBoxObj.getArray()->incRef();
-    pageDict->add(copyString("TrimBox"), &mediaBoxObj);
+    mediaBoxArray->incRef();
+    pageDict->add(copyString("TrimBox"), Object(mediaBoxArray));
   }
-  Object rotateObj;
-  rotateObj.initInt(rotate);
-  pageDict->add(copyString("Rotate"), &rotateObj);
+  pageDict->add(copyString("Rotate"), Object(rotate));
   getXRef()->setModifiedObject(&page, *refPage);
-  page.free();
 }
 
 void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum) 
@@ -1703,7 +1593,7 @@ void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint n
 
   for (int n = 0; n < pageDict->getLength(); n++) {
     const char *key = pageDict->getKey(n);
-    Object value; pageDict->getValNF(n, &value);
+    Object value  = pageDict->getValNF(n);
     if (strcmp(key, "Parent") != 0 &&
 	      strcmp(key, "Pages") != 0 &&
 	      strcmp(key, "AcroForm") != 0 &&
@@ -1712,73 +1602,48 @@ void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint n
         strcmp(key, "Root") != 0) {
       markObject(&value, xRef, countRef, numOffset, oldRefNum, newRefNum);
     }
-    value.free();
   }
 }
 
 GBool PDFDoc::markAnnotations(Object *annotsObj, XRef *xRef, XRef *countRef, Guint numOffset, int oldPageNum, int newPageNum) {
-  Object annots;
   GBool modified = gFalse;
-  annotsObj->fetch(getXRef(), &annots);
+  Object annots = annotsObj->fetch(getXRef());
   if (annots.isArray()) {
       Array *array = annots.getArray();
       for (int i=array->getLength() - 1; i >= 0; i--) {
-        Object obj1;
-        if (array->get(i, &obj1)->isDict()) {
-          Object type;
+        Object obj1 = array->get(i);
+        if (obj1.isDict()) {
           Dict *dict = obj1.getDict();
-          dict->lookup("Type", &type);
+          Object type = dict->lookup("Type");
           if (type.isName() && strcmp(type.getName(), "Annot") == 0) {
-            Object obj2;
-            if (dict->lookupNF("P", &obj2)->isRef()) {
+            Object obj2 = dict->lookupNF("P");
+            if (obj2.isRef()) {
               if (obj2.getRef().num == oldPageNum) {
-                Object obj3;
-                array->getNF(i, &obj3);
+                Object obj3 = array->getNF(i);
                 if (obj3.isRef()) {
-                  Object newRef;
-                  newRef.initRef(newPageNum, 0);
-                  dict->set("P", &newRef);
+                  dict->set("P", Object(newPageNum, 0));
                   getXRef()->setModifiedObject(&obj1, obj3.getRef());
                 }
-                obj3.free();
               } else if (obj2.getRef().num == newPageNum) {
-                obj1.free();
-                obj2.free();
-                type.free();
                 continue;
               } else {
-                Object page;
-                getXRef()->fetch(obj2.getRef().num, obj2.getRef().gen, &page);
+                Object page  = getXRef()->fetch(obj2.getRef().num, obj2.getRef().gen);
                 if (page.isDict()) {
-                  Object pagetype;
                   Dict *dict = page.getDict();
-                  dict->lookup("Type", &pagetype);
+                  Object pagetype = dict->lookup("Type");
                   if (!pagetype.isName() || strcmp(pagetype.getName(), "Page") != 0) {
-                    obj1.free();
-                    obj2.free();
-                    type.free();
-                    page.free();
-                    pagetype.free();
                     continue;
                   }
-                  pagetype.free();
                 }
-                page.free();
-                obj1.free();
-                obj2.free();
-                type.free();
                 array->remove(i);
                 modified = gTrue;
                 continue;
               }
             }
-            obj2.free();
           }
-          type.free();
           markPageObjects(dict, xRef, countRef, numOffset, oldPageNum, newPageNum);
         }
-        obj1.free();
-        array->getNF(i, &obj1);
+        obj1 = array->getNF(i);
         if (obj1.isRef()) {
           if (obj1.getRef().num + (int) numOffset >= xRef->getNumObjects() || xRef->getEntry(obj1.getRef().num + numOffset)->type == xrefEntryFree) {
             if (getXRef()->getEntry(obj1.getRef().num)->type == xrefEntryFree) {
@@ -1798,7 +1663,6 @@ GBool PDFDoc::markAnnotations(Object *annotsObj, XRef *xRef, XRef *countRef, Gui
             entry->gen++;
           } 
         }
-        obj1.free();
       }
   }
   if (annotsObj->isRef()) {
@@ -1821,25 +1685,21 @@ GBool PDFDoc::markAnnotations(Object *annotsObj, XRef *xRef, XRef *countRef, Gui
     } 
     getXRef()->setModifiedObject(&annots, annotsObj->getRef());
   }
-  annots.free();
   return modified;
 }
 
 void PDFDoc::markAcroForm(Object *afObj, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum) {
-  Object acroform;
   GBool modified = gFalse;
-  afObj->fetch(getXRef(), &acroform);
+  Object acroform = afObj->fetch(getXRef());
   if (acroform.isDict()) {
       Dict *dict = acroform.getDict();
       for (int i=0; i < dict->getLength(); i++) {
         if (strcmp(dict->getKey(i), "Fields") == 0) {
-          Object fields;
-          modified = markAnnotations(dict->getValNF(i, &fields), xRef, countRef, numOffset, oldRefNum, newRefNum);
-          fields.free();
+          Object fields = dict->getValNF(i);
+          modified = markAnnotations(&fields, xRef, countRef, numOffset, oldRefNum, newRefNum);
         } else {
-          Object obj;
-          markObject(dict->getValNF(i, &obj), xRef, countRef, numOffset, oldRefNum, newRefNum);
-          obj.free();
+          Object obj = dict->getValNF(i);
+          markObject(&obj, xRef, countRef, numOffset, oldRefNum, newRefNum);
         }
       }
   }
@@ -1865,7 +1725,6 @@ void PDFDoc::markAcroForm(Object *afObj, XRef *xRef, XRef *countRef, Guint numOf
       getXRef()->setModifiedObject(&acroform, afObj->getRef());
     }
   }
-  acroform.free();
   return;
 }
 
@@ -1879,12 +1738,11 @@ Guint PDFDoc::writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset, G
 
   for (int n = numOffset; n < xRef->getNumObjects(); n++) {
     if (xRef->getEntry(n)->type != xrefEntryFree) {
-      Object obj;
       Ref ref;
       ref.num = n;
       ref.gen = xRef->getEntry(n)->gen;
       objectsCount++;
-      getXRef()->fetch(ref.num - numOffset, ref.gen, &obj);
+      Object obj = getXRef()->fetch(ref.num - numOffset, ref.gen);
       Goffset offset = writeObjectHeader(&ref, outStr);
       if (combine) {
         writeObject(&obj, outStr, getXRef(), numOffset, NULL, cryptRC4, 0, 0, 0);
@@ -1895,7 +1753,6 @@ Guint PDFDoc::writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset, G
       }
       writeObjectFooter(outStr);
       xRef->add(ref.num, ref.gen, offset, gTrue);
-      obj.free();
     }
   }
   return objectsCount;
@@ -2032,8 +1889,6 @@ int PDFDoc::getNumPages()
 
 Page *PDFDoc::parsePage(int page)
 {
-  Page *p = NULL;
-  Object obj;
   Ref pageRef;
   Dict *pageDict;
 
@@ -2050,19 +1905,15 @@ Page *PDFDoc::parsePage(int page)
   }
 
   pageRef.gen = xref->getEntry(pageRef.num)->gen;
-  xref->fetch(pageRef.num, pageRef.gen, &obj);
+  Object obj = xref->fetch(pageRef.num, pageRef.gen);
   if (!obj.isDict("Page")) {
-    obj.free();
     error(errSyntaxWarning, -1, "Object ({0:d} {1:d}) is not a pageDict", pageRef.num, pageRef.gen);
     return NULL;
   }
   pageDict = obj.getDict();
 
-  p = new Page(this, page, pageDict, pageRef,
+  return new Page(this, page, pageDict, pageRef,
                new PageAttrs(NULL, pageDict), catalog->getForm());
-  obj.free();
-
-  return p;
 }
 
 Page *PDFDoc::getPage(int page)
diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h
index 99de8a21..d379b1cf 100644
--- a/poppler/PDFDoc.h
+++ b/poppler/PDFDoc.h
@@ -229,12 +229,12 @@ public:
   GBool isLinearized(GBool tryingToReconstruct = gFalse);
 
   // Return the document's Info dictionary (if any).
-  Object *getDocInfo(Object *obj) { return xref->getDocInfo(obj); }
-  Object *getDocInfoNF(Object *obj) { return xref->getDocInfoNF(obj); }
+  Object getDocInfo() { return xref->getDocInfo(); }
+  Object getDocInfoNF() { return xref->getDocInfoNF(); }
 
   // Create and return the document's Info dictionary if none exists.
   // Otherwise return the existing one.
-  Object *createDocInfoIfNoneExists(Object *obj) { return xref->createDocInfoIfNoneExists(obj); }
+  Object createDocInfoIfNoneExists() { return xref->createDocInfoIfNoneExists(); }
 
   // Remove the document's Info dictionary and update the trailer dictionary.
   void removeDocInfo() { xref->removeDocInfo(); }
diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index c7a6057d..cec42692 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -1533,7 +1533,6 @@ PSOutputDev::~PSOutputDev() {
 void PSOutputDev::writeHeader(const std::vector<int> &pages,
 			      PDFRectangle *mediaBox, PDFRectangle *cropBox,
 			      int pageRotate, char *psTitle) {
-  Object info, obj1;
   PSOutPaperSize *size;
   double x1, y1, x2, y2;
   int i;
@@ -1550,13 +1549,14 @@ void PSOutputDev::writeHeader(const std::vector<int> &pages,
     break;
   }
   writePSFmt("%Produced by poppler pdftops version: {0:s} (http://poppler.freedesktop.org)\n", PACKAGE_VERSION);
-  xref->getDocInfo(&info);
-  if (info.isDict() && info.dictLookup("Creator", &obj1)->isString()) {
-    writePS("%%Creator: ");
-    writePSTextLine(obj1.getString());
+  Object info = xref->getDocInfo();
+  if (info.isDict()) {
+    Object obj1 = info.dictLookup("Creator");
+    if (obj1.isString()) {
+        writePS("%%Creator: ");
+        writePSTextLine(obj1.getString());
+    }
   }
-  obj1.free();
-  info.free();
   if(psTitle) {
     char *sanitizedTitle = strdup(psTitle);
     for (Guint i = 0; i < strlen(sanitizedTitle); ++i) {
@@ -1677,9 +1677,7 @@ void PSOutputDev::writeDocSetup(PDFDoc *doc, Catalog *catalog,
   Dict *resDict;
   Annots *annots;
   Object *acroForm;
-  Object obj1, obj2, obj3;
   GooString *s;
-  int i;
 
   if (mode == psModeForm) {
     // swap the form and xpdf dicts
@@ -1698,30 +1696,30 @@ void PSOutputDev::writeDocSetup(PDFDoc *doc, Catalog *catalog,
       setupResources(resDict);
     }
     annots = page->getAnnots();
-    for (i = 0; i < annots->getNumAnnots(); ++i) {
-      if (annots->getAnnot(i)->getAppearanceResDict(&obj1)->isDict()) {
+    for (int i = 0; i < annots->getNumAnnots(); ++i) {
+      Object obj1 = annots->getAnnot(i)->getAppearanceResDict();
+      if (obj1.isDict()) {
         setupResources(obj1.getDict());
       }
-      obj1.free();
     }
   }
   if ((acroForm = catalog->getAcroForm()) && acroForm->isDict()) {
-    if (acroForm->dictLookup("DR", &obj1)->isDict()) {
+    Object obj1 = acroForm->dictLookup("DR");
+    if (obj1.isDict()) {
       setupResources(obj1.getDict());
     }
-    obj1.free();
-    if (acroForm->dictLookup("Fields", &obj1)->isArray()) {
-      for (i = 0; i < obj1.arrayGetLength(); ++i) {
-	if (obj1.arrayGet(i, &obj2)->isDict()) {
-	  if (obj2.dictLookup("DR", &obj3)->isDict()) {
+    obj1 = acroForm->dictLookup("Fields");
+    if (obj1.isArray()) {
+      for (int i = 0; i < obj1.arrayGetLength(); ++i) {
+	Object obj2 = obj1.arrayGet(i);
+	if (obj2.isDict()) {
+	  Object obj3 = obj2.dictLookup("DR");
+	  if (obj3.isDict()) {
 	    setupResources(obj3.getDict());
 	  }
-	  obj3.free();
 	}
-	obj2.free();
       }
     }
-    obj1.free();
   }
   if (mode != psModeForm) {
     if (mode != psModeEPS && !manualCtrl) {
@@ -1795,24 +1793,22 @@ void PSOutputDev::writeTrailer() {
 }
 
 void PSOutputDev::setupResources(Dict *resDict) {
-  Object xObjDict, xObjRef, xObj, patDict, patRef, pat, resObj;
-  Ref ref0;
   GBool skip;
-  int i;
 
   setupFonts(resDict);
   setupImages(resDict);
   setupForms(resDict);
 
   //----- recursively scan XObjects
-  resDict->lookup("XObject", &xObjDict);
+  Object xObjDict = resDict->lookup("XObject");
   if (xObjDict.isDict()) {
-    for (i = 0; i < xObjDict.dictGetLength(); ++i) {
+    for (int i = 0; i < xObjDict.dictGetLength(); ++i) {
 
       // avoid infinite recursion on XObjects
       skip = gFalse;
-      if ((xObjDict.dictGetValNF(i, &xObjRef)->isRef())) {
-	ref0 = xObjRef.getRef();
+      Object xObjRef = xObjDict.dictGetValNF(i);
+      if (xObjRef.isRef()) {
+	Ref ref0 = xObjRef.getRef();
 	if (resourceIDs.find(ref0.num) != resourceIDs.end()) {
 	  skip = gTrue;
 	} else {
@@ -1822,32 +1818,28 @@ void PSOutputDev::setupResources(Dict *resDict) {
       if (!skip) {
 
 	// process the XObject's resource dictionary
-	xObjDict.dictGetVal(i, &xObj);
+	Object xObj = xObjDict.dictGetVal(i);
 	if (xObj.isStream()) {
-	  xObj.streamGetDict()->lookup("Resources", &resObj);
+	  Object resObj = xObj.streamGetDict()->lookup("Resources");
 	  if (resObj.isDict()) {
 	    setupResources(resObj.getDict());
 	  }
-	  resObj.free();
 	}
-	xObj.free();
       }
-
-      xObjRef.free();
     }
   }
-  xObjDict.free();
 
   //----- recursively scan Patterns
-  resDict->lookup("Pattern", &patDict);
+  Object patDict = resDict->lookup("Pattern");
   if (patDict.isDict()) {
     inType3Char = gTrue;
-    for (i = 0; i < patDict.dictGetLength(); ++i) {
+    for (int i = 0; i < patDict.dictGetLength(); ++i) {
 
       // avoid infinite recursion on Patterns
       skip = gFalse;
-      if ((patDict.dictGetValNF(i, &patRef)->isRef())) {
-	ref0 = patRef.getRef();
+      Object patRef = patDict.dictGetValNF(i);
+      if (patRef.isRef()) {
+	Ref ref0 = patRef.getRef();
 	if (resourceIDs.find(ref0.num) != resourceIDs.end()) {
 	  skip = gTrue;
 	} else {
@@ -1857,40 +1849,33 @@ void PSOutputDev::setupResources(Dict *resDict) {
       if (!skip) {
 
 	// process the Pattern's resource dictionary
-	patDict.dictGetVal(i, &pat);
+	Object pat = patDict.dictGetVal(i);
 	if (pat.isStream()) {
-	  pat.streamGetDict()->lookup("Resources", &resObj);
+	  Object resObj = pat.streamGetDict()->lookup("Resources");
 	  if (resObj.isDict()) {
 	    setupResources(resObj.getDict());
 	  }
-	  resObj.free();
 	}
-	pat.free();
       }
-
-      patRef.free();
     }
     inType3Char = gFalse;
   }
-  patDict.free();
 }
 
 void PSOutputDev::setupFonts(Dict *resDict) {
-  Object obj1, obj2;
   Ref r;
   GfxFontDict *gfxFontDict;
   GfxFont *font;
   int i;
 
-  gfxFontDict = NULL;
-  resDict->lookupNF("Font", &obj1);
+  gfxFontDict = nullptr;
+  Object obj1 = resDict->lookupNF("Font");
   if (obj1.isRef()) {
-    obj1.fetch(xref, &obj2);
+    Object obj2 = obj1.fetch(xref);
     if (obj2.isDict()) {
       r = obj1.getRef();
       gfxFontDict = new GfxFontDict(xref, &r, obj2.getDict());
     }
-    obj2.free();
   } else if (obj1.isDict()) {
     gfxFontDict = new GfxFontDict(xref, NULL, obj1.getDict());
   }
@@ -1902,7 +1887,6 @@ void PSOutputDev::setupFonts(Dict *resDict) {
     }
     delete gfxFontDict;
   }
-  obj1.free();
 }
 
 void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
@@ -2136,14 +2120,12 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
 
 void PSOutputDev::setupEmbeddedType1Font(Ref *id, GooString *psName) {
   static const char hexChar[17] = "0123456789abcdef";
-  Object refObj, strObj, obj1, obj2, obj3;
   Dict *dict;
   long length1, length2, length3;
-  int c;
+  int c, i;
   int start[4];
   GBool binMode;
   GBool writePadding = gTrue;
-  int i;
 
   // check if font is already embedded
   if (fontNames->lookupInt(psName)) {
@@ -2152,9 +2134,9 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, GooString *psName) {
   fontNames->add(psName->copy(), 1);
 
   // get the font stream and info
-  refObj.initRef(id->num, id->gen);
-  refObj.fetch(xref, &strObj);
-  refObj.free();
+  Object obj1, obj2, obj3;
+  Object refObj(id->num, id->gen);
+  Object strObj = refObj.fetch(xref);
   if (!strObj.isStream()) {
     error(errSyntaxError, -1, "Embedded font file object is not a stream");
     goto err1;
@@ -2164,23 +2146,17 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, GooString *psName) {
 	  "Embedded font stream is missing its dictionary");
     goto err1;
   }
-  dict->lookup("Length1", &obj1);
-  dict->lookup("Length2", &obj2);
-  dict->lookup("Length3", &obj3);
+  obj1 = dict->lookup("Length1");
+  obj2 = dict->lookup("Length2");
+  obj3 = dict->lookup("Length3");
   if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) {
     error(errSyntaxError, -1,
 	  "Missing length fields in embedded font stream dictionary");
-    obj1.free();
-    obj2.free();
-    obj3.free();
     goto err1;
   }
   length1 = obj1.getInt();
   length2 = obj2.getInt();
   length3 = obj3.getInt();
-  obj1.free();
-  obj2.free();
-  obj3.free();
 
   // beginning comment
   writePSFmt("%%BeginResource: font {0:t}\n", psName);
@@ -2324,7 +2300,6 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, GooString *psName) {
  err1:
   if (strObj.isStream())
     strObj.streamClose();
-  strObj.free();
 }
 
 void PSOutputDev::setupExternalType1Font(GooString *fileName, GooString *psName) {
@@ -2796,7 +2771,6 @@ void PSOutputDev::setupType3Font(GfxFont *font, GooString *psName,
 				 Dict *parentResDict) {
   Dict *resDict;
   Dict *charProcs;
-  Object charProc;
   Gfx *gfx;
   PDFRectangle box;
   double *m;
@@ -2854,8 +2828,8 @@ void PSOutputDev::setupType3Font(GfxFont *font, GooString *psName,
       writePS("/");
       writePSName(charProcs->getKey(i));
       writePS(" {\n");
-      gfx->display(charProcs->getVal(i, &charProc));
-      charProc.free();
+      Object charProc = charProcs->getVal(i);
+      gfx->display(&charProc);
       if (t3String) {
 	if (t3Cacheable) {
 	  buf = GooString::format("{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} setcachedevice\n",
@@ -2922,25 +2896,24 @@ GooString *PSOutputDev::makePSFontName(GfxFont *font, Ref *id) {
 }
 
 void PSOutputDev::setupImages(Dict *resDict) {
-  Object xObjDict, xObj, xObjRef, subtypeObj, maskObj, maskRef;
   Ref imgID;
-  int i, j;
 
   if (!(mode == psModeForm || inType3Char || preloadImagesForms)) {
     return;
   }
 
   //----- recursively scan XObjects
-  resDict->lookup("XObject", &xObjDict);
+  Object xObjDict = resDict->lookup("XObject");
   if (xObjDict.isDict()) {
-    for (i = 0; i < xObjDict.dictGetLength(); ++i) {
-      xObjDict.dictGetValNF(i, &xObjRef);
-      xObjDict.dictGetVal(i, &xObj);
+    for (int i = 0; i < xObjDict.dictGetLength(); ++i) {
+      Object xObjRef = xObjDict.dictGetValNF(i);
+      Object xObj = xObjDict.dictGetVal(i);
       if (xObj.isStream()) {
-	xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
+	Object subtypeObj = xObj.streamGetDict()->lookup("Subtype");
 	if (subtypeObj.isName("Image")) {
 	  if (xObjRef.isRef()) {
 	    imgID = xObjRef.getRef();
+	    int j;
 	    for (j = 0; j < imgIDLen; ++j) {
 	      if (imgIDs[j].num == imgID.num && imgIDs[j].gen == imgID.gen) {
 		break;
@@ -2957,24 +2930,21 @@ void PSOutputDev::setupImages(Dict *resDict) {
 	      }
 	      imgIDs[imgIDLen++] = imgID;
 	      setupImage(imgID, xObj.getStream(), gFalse);
-	      if (level >= psLevel3 &&
-		  xObj.streamGetDict()->lookup("Mask", &maskObj)->isStream()) {
-		setupImage(imgID, maskObj.getStream(), gTrue);
+	      if (level >= psLevel3) {
+		Object maskObj = xObj.streamGetDict()->lookup("Mask");
+		if (maskObj.isStream()) {
+		  setupImage(imgID, maskObj.getStream(), gTrue);
+		}
 	      }
-	      maskObj.free();
 	    }
 	  } else {
 	    error(errSyntaxError, -1,
 		  "Image in resource dict is not an indirect reference");
 	  }
 	}
-	subtypeObj.free();
       }
-      xObj.free();
-      xObjRef.free();
     }
   }
-  xObjDict.free();
 }
 
 void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
@@ -3146,20 +3116,17 @@ void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
 }
 
 void PSOutputDev::setupForms(Dict *resDict) {
-  Object xObjDict, xObj, xObjRef, subtypeObj;
-  int i;
-
   if (!preloadImagesForms) {
     return;
   }
 
-  resDict->lookup("XObject", &xObjDict);
+  Object xObjDict = resDict->lookup("XObject");
   if (xObjDict.isDict()) {
-    for (i = 0; i < xObjDict.dictGetLength(); ++i) {
-      xObjDict.dictGetValNF(i, &xObjRef);
-      xObjDict.dictGetVal(i, &xObj);
+    for (int i = 0; i < xObjDict.dictGetLength(); ++i) {
+      Object xObjRef = xObjDict.dictGetValNF(i);
+      Object xObj = xObjDict.dictGetVal(i);
       if (xObj.isStream()) {
-	xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
+	Object subtypeObj = xObj.streamGetDict()->lookup("Subtype");
 	if (subtypeObj.isName("Form")) {
 	  if (xObjRef.isRef()) {
 	    setupForm(xObjRef.getRef(), &xObj);
@@ -3168,25 +3135,19 @@ void PSOutputDev::setupForms(Dict *resDict) {
 		  "Form in resource dict is not an indirect reference");
 	  }
 	}
-	subtypeObj.free();
       }
-      xObj.free();
-      xObjRef.free();
     }
   }
-  xObjDict.free();
 }
 
 void PSOutputDev::setupForm(Ref id, Object *strObj) {
   Dict *dict, *resDict;
-  Object matrixObj, bboxObj, resObj, obj1;
   double m[6], bbox[4];
   PDFRectangle box;
   Gfx *gfx;
-  int i;
 
   // check if form is already defined
-  for (i = 0; i < formIDLen; ++i) {
+  for (int i = 0; i < formIDLen; ++i) {
     if (formIDs[i].num == id.num && formIDs[i].gen == id.gen) {
       return;
     }
@@ -3206,36 +3167,31 @@ void PSOutputDev::setupForm(Ref id, Object *strObj) {
   dict = strObj->streamGetDict();
 
   // get bounding box
-  dict->lookup("BBox", &bboxObj);
+  Object bboxObj = dict->lookup("BBox");
   if (!bboxObj.isArray()) {
-    bboxObj.free();
     error(errSyntaxError, -1, "Bad form bounding box");
     return;
   }
-  for (i = 0; i < 4; ++i) {
-    bboxObj.arrayGet(i, &obj1);
+  for (int i = 0; i < 4; ++i) {
+    Object obj1 = bboxObj.arrayGet(i);
     bbox[i] = obj1.getNum();
-    obj1.free();
   }
-  bboxObj.free();
 
   // get matrix
-  dict->lookup("Matrix", &matrixObj);
+  Object matrixObj = dict->lookup("Matrix");
   if (matrixObj.isArray()) {
-    for (i = 0; i < 6; ++i) {
-      matrixObj.arrayGet(i, &obj1);
+    for (int i = 0; i < 6; ++i) {
+      Object obj1 = matrixObj.arrayGet(i);
       m[i] = obj1.getNum();
-      obj1.free();
     }
   } else {
     m[0] = 1; m[1] = 0;
     m[2] = 0; m[3] = 1;
     m[4] = 0; m[5] = 0;
   }
-  matrixObj.free();
 
   // get resources
-  dict->lookup("Resources", &resObj);
+  Object resObj = dict->lookup("Resources");
   resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
 
   writePSFmt("/f_{0:d}_{1:d} {{\n", id.num, id.gen);
@@ -3253,8 +3209,6 @@ void PSOutputDev::setupForm(Ref id, Object *strObj) {
 
   writePS("Q\n");
   writePS("} def\n");
-
-  resObj.free();
 }
 
 GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
@@ -3276,7 +3230,6 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
   GfxState *state;
   SplashBitmap *bitmap;
   Stream *str0, *str;
-  Object obj;
   Guchar *p;
   Guchar col[4];
   double hDPI2, vDPI2;
@@ -3594,9 +3547,8 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
     case psLevel2Sep:
     case psLevel3:
     case psLevel3Sep:
-      obj.initNull();
       p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize();
-      str0 = new MemStream((char *)p, 0, w * h * numComps, &obj);
+      str0 = new MemStream((char *)p, 0, w * h * numComps, Object(objNull));
       // Check for a color image that uses only gray
       if (!getOptimizeColorSpace()) {
 	isGray = gFalse;
@@ -6880,138 +6832,111 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace,
 
 #if OPI_SUPPORT
 void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) {
-  Object dict;
-
   if (generateOPI) {
-    opiDict->lookup("2.0", &dict);
+    Object dict = opiDict->lookup("2.0");
     if (dict.isDict()) {
       opiBegin20(state, dict.getDict());
-      dict.free();
     } else {
-      dict.free();
-      opiDict->lookup("1.3", &dict);
+      dict = opiDict->lookup("1.3");
       if (dict.isDict()) {
 	opiBegin13(state, dict.getDict());
       }
-      dict.free();
     }
   }
 }
 
 void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
-  Object obj1, obj2, obj3, obj4;
   double width, height, left, right, top, bottom;
   int w, h;
-  int i;
 
   writePS("%%BeginOPI: 2.0\n");
   writePS("%%Distilled\n");
 
-  dict->lookup("F", &obj1);
-  if (getFileSpecName(&obj1, &obj2)) {
+  Object obj1 = dict->lookup("F");
+  Object obj2 = getFileSpecName(&obj1);
+  if (obj2.isString()) {
     writePSFmt("%%ImageFileName: {0:t}\n", obj2.getString());
-    obj2.free();
   }
-  obj1.free();
 
-  dict->lookup("MainImage", &obj1);
+  obj1 = dict->lookup("MainImage");
   if (obj1.isString()) {
     writePSFmt("%%MainImage: {0:t}\n", obj1.getString());
   }
-  obj1.free();
 
   //~ ignoring 'Tags' entry
   //~ need to use writePSString() and deal with >255-char lines
 
-  dict->lookup("Size", &obj1);
+  obj1 = dict->lookup("Size");
   if (obj1.isArray() && obj1.arrayGetLength() == 2) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     width = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     height = obj2.getNum();
-    obj2.free();
     writePSFmt("%%ImageDimensions: {0:.6g} {1:.6g}\n", width, height);
   }
-  obj1.free();
 
-  dict->lookup("CropRect", &obj1);
+  obj1 = dict->lookup("CropRect");
   if (obj1.isArray() && obj1.arrayGetLength() == 4) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     left = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     top = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(2, &obj2);
+    obj2 = obj1.arrayGet(2);
     right = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(3, &obj2);
+    obj2 = obj1.arrayGet(3);
     bottom = obj2.getNum();
-    obj2.free();
     writePSFmt("%%ImageCropRect: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
 	       left, top, right, bottom);
   }
-  obj1.free();
 
-  dict->lookup("Overprint", &obj1);
+  obj1 = dict->lookup("Overprint");
   if (obj1.isBool()) {
     writePSFmt("%%ImageOverprint: {0:s}\n", obj1.getBool() ? "true" : "false");
   }
-  obj1.free();
 
-  dict->lookup("Inks", &obj1);
+  obj1 = dict->lookup("Inks");
   if (obj1.isName()) {
     writePSFmt("%%ImageInks: {0:s}\n", obj1.getName());
   } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     if (obj2.isName()) {
       writePSFmt("%%ImageInks: {0:s} {1:d}",
 		 obj2.getName(), (obj1.arrayGetLength() - 1) / 2);
-      for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) {
-	obj1.arrayGet(i, &obj3);
-	obj1.arrayGet(i+1, &obj4);
+      for (int i = 1; i+1 < obj1.arrayGetLength(); i += 2) {
+	Object obj3 = obj1.arrayGet(i);
+	Object obj4 = obj1.arrayGet(i+1);
 	if (obj3.isString() && obj4.isNum()) {
 	  writePS(" ");
 	  writePSString(obj3.getString());
 	  writePSFmt(" {0:.6g}", obj4.getNum());
 	}
-	obj3.free();
-	obj4.free();
       }
       writePS("\n");
     }
-    obj2.free();
   }
-  obj1.free();
 
   writePS("gsave\n");
 
   writePS("%%BeginIncludedImage\n");
 
-  dict->lookup("IncludedImageDimensions", &obj1);
+  obj1 = dict->lookup("IncludedImageDimensions");
   if (obj1.isArray() && obj1.arrayGetLength() == 2) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     w = obj2.getInt();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     h = obj2.getInt();
-    obj2.free();
     writePSFmt("%%IncludedImageDimensions: {0:d} {1:d}\n", w, h);
   }
-  obj1.free();
 
-  dict->lookup("IncludedImageQuality", &obj1);
+  obj1 = dict->lookup("IncludedImageQuality");
   if (obj1.isNum()) {
     writePSFmt("%%IncludedImageQuality: {0:.6g}\n", obj1.getNum());
   }
-  obj1.free();
 
   ++opi20Nest;
 }
 
 void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
-  Object obj1, obj2;
   int left, right, top, bottom, samples, bits, width, height;
   double c, m, y, k;
   double llx, lly, ulx, uly, urx, ury, lrx, lry;
@@ -7023,86 +6948,68 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
   writePS("/opiMatrix2 matrix currentmatrix def\n");
   writePS("opiMatrix setmatrix\n");
 
-  dict->lookup("F", &obj1);
-  if (getFileSpecName(&obj1, &obj2)) {
+  Object obj1 = dict->lookup("F");
+  Object obj2 = getFileSpecName(&obj1);
+  if (obj2.isString()) {
     writePSFmt("%ALDImageFileName: {0:t}\n", obj2.getString());
-    obj2.free();
   }
-  obj1.free();
 
-  dict->lookup("CropRect", &obj1);
+  obj1 = dict->lookup("CropRect");
   if (obj1.isArray() && obj1.arrayGetLength() == 4) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     left = obj2.getInt();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     top = obj2.getInt();
-    obj2.free();
-    obj1.arrayGet(2, &obj2);
+    obj2 = obj1.arrayGet(2);
     right = obj2.getInt();
-    obj2.free();
-    obj1.arrayGet(3, &obj2);
+    obj2 = obj1.arrayGet(3);
     bottom = obj2.getInt();
-    obj2.free();
     writePSFmt("%ALDImageCropRect: {0:d} {1:d} {2:d} {3:d}\n",
 	       left, top, right, bottom);
   }
-  obj1.free();
 
-  dict->lookup("Color", &obj1);
+  obj1 = dict->lookup("Color");
   if (obj1.isArray() && obj1.arrayGetLength() == 5) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     c = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     m = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(2, &obj2);
+    obj2 = obj1.arrayGet(2);
     y = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(3, &obj2);
+    obj2 = obj1.arrayGet(3);
     k = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(4, &obj2);
+    obj2 = obj1.arrayGet(4);
     if (obj2.isString()) {
       writePSFmt("%ALDImageColor: {0:.4g} {1:.4g} {2:.4g} {3:.4g} ",
 		 c, m, y, k);
       writePSString(obj2.getString());
       writePS("\n");
     }
-    obj2.free();
   }
-  obj1.free();
 
-  dict->lookup("ColorType", &obj1);
+  obj1 = dict->lookup("ColorType");
   if (obj1.isName()) {
     writePSFmt("%ALDImageColorType: {0:s}\n", obj1.getName());
   }
-  obj1.free();
 
   //~ ignores 'Comments' entry
   //~ need to handle multiple lines
 
-  dict->lookup("CropFixed", &obj1);
+  obj1 = dict->lookup("CropFixed");
   if (obj1.isArray()) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     ulx = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     uly = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(2, &obj2);
+    obj2 = obj1.arrayGet(2);
     lrx = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(3, &obj2);
+    obj2 = obj1.arrayGet(3);
     lry = obj2.getNum();
-    obj2.free();
     writePSFmt("%ALDImageCropFixed: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
 	       ulx, uly, lrx, lry);
   }
-  obj1.free();
 
-  dict->lookup("GrayMap", &obj1);
+  obj1 = dict->lookup("GrayMap");
   if (obj1.isArray()) {
     writePS("%ALDImageGrayMap:");
     for (i = 0; i < obj1.arrayGetLength(); i += 16) {
@@ -7110,116 +7017,90 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
 	writePS("\n%%+");
       }
       for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) {
-	obj1.arrayGet(i+j, &obj2);
+	obj2 = obj1.arrayGet(i+j);
 	writePSFmt(" {0:d}", obj2.getInt());
-	obj2.free();
       }
     }
     writePS("\n");
   }
-  obj1.free();
 
-  dict->lookup("ID", &obj1);
+  obj1 = dict->lookup("ID");
   if (obj1.isString()) {
     writePSFmt("%ALDImageID: {0:t}\n", obj1.getString());
   }
-  obj1.free();
 
-  dict->lookup("ImageType", &obj1);
+  obj1 = dict->lookup("ImageType");
   if (obj1.isArray() && obj1.arrayGetLength() == 2) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     samples = obj2.getInt();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     bits = obj2.getInt();
-    obj2.free();
     writePSFmt("%ALDImageType: {0:d} {1:d}\n", samples, bits);
   }
-  obj1.free();
 
-  dict->lookup("Overprint", &obj1);
+  dict->lookup("Overprint");
   if (obj1.isBool()) {
     writePSFmt("%ALDImageOverprint: {0:s}\n",
 	       obj1.getBool() ? "true" : "false");
   }
-  obj1.free();
 
-  dict->lookup("Position", &obj1);
+  obj1 = dict->lookup("Position");
   if (obj1.isArray() && obj1.arrayGetLength() == 8) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     llx = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     lly = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(2, &obj2);
+    obj2 = obj1.arrayGet(2);
     ulx = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(3, &obj2);
+    obj2 = obj1.arrayGet(3);
     uly = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(4, &obj2);
+    obj2 = obj1.arrayGet(4);
     urx = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(5, &obj2);
+    obj2 = obj1.arrayGet(5);
     ury = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(6, &obj2);
+    obj2 = obj1.arrayGet(6);
     lrx = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(7, &obj2);
+    obj2 = obj1.arrayGet(7);
     lry = obj2.getNum();
-    obj2.free();
     opiTransform(state, llx, lly, &tllx, &tlly);
     opiTransform(state, ulx, uly, &tulx, &tuly);
     opiTransform(state, urx, ury, &turx, &tury);
     opiTransform(state, lrx, lry, &tlrx, &tlry);
     writePSFmt("%ALDImagePosition: {0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} {6:.6g} {7:.6g}\n",
 	       tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry);
-    obj2.free();
   }
-  obj1.free();
 
-  dict->lookup("Resolution", &obj1);
+  obj1 = dict->lookup("Resolution");
   if (obj1.isArray() && obj1.arrayGetLength() == 2) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     horiz = obj2.getNum();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     vert = obj2.getNum();
-    obj2.free();
     writePSFmt("%ALDImageResoution: {0:.6g} {1:.6g}\n", horiz, vert);
-    obj2.free();
   }
-  obj1.free();
 
-  dict->lookup("Size", &obj1);
+  obj1 = dict->lookup("Size");
   if (obj1.isArray() && obj1.arrayGetLength() == 2) {
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     width = obj2.getInt();
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     height = obj2.getInt();
-    obj2.free();
     writePSFmt("%ALDImageDimensions: {0:d} {1:d}\n", width, height);
   }
-  obj1.free();
 
   //~ ignoring 'Tags' entry
   //~ need to use writePSString() and deal with >255-char lines
 
-  dict->lookup("Tint", &obj1);
+  obj1 = dict->lookup("Tint");
   if (obj1.isNum()) {
     writePSFmt("%ALDImageTint: {0:.6g}\n", obj1.getNum());
   }
-  obj1.free();
 
-  dict->lookup("Transparency", &obj1);
+  obj1 = dict->lookup("Transparency");
   if (obj1.isBool()) {
     writePSFmt("%ALDImageTransparency: {0:s}\n",
 	       obj1.getBool() ? "true" : "false");
   }
-  obj1.free();
 
   writePS("%%BeginObject: image\n");
   writePS("opiMatrix2 setmatrix\n");
@@ -7253,25 +7134,20 @@ void PSOutputDev::opiTransform(GfxState *state, double x0, double y0,
 }
 
 void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) {
-  Object dict;
-
   if (generateOPI) {
-    opiDict->lookup("2.0", &dict);
+    Object dict = opiDict->lookup("2.0");
     if (dict.isDict()) {
       writePS("%%EndIncludedImage\n");
       writePS("%%EndOPI\n");
       writePS("grestore\n");
       --opi20Nest;
-      dict.free();
     } else {
-      dict.free();
-      opiDict->lookup("1.3", &dict);
+      dict = opiDict->lookup("1.3");
       if (dict.isDict()) {
 	writePS("%%EndObject\n");
 	writePS("restore\n");
 	--opi13Nest;
       }
-      dict.free();
     }
   }
 }
diff --git a/poppler/Page.cc b/poppler/Page.cc
index cf687c03..b8002023 100644
--- a/poppler/Page.cc
+++ b/poppler/Page.cc
@@ -108,7 +108,7 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
     cropBox = attrs->cropBox;
     haveCropBox = attrs->haveCropBox;
     rotate = attrs->rotate;
-    attrs->resources.copy(&resources);
+    resources = attrs->resources.copy();
   } else {
     // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary
     // but some (non-compliant) PDF files don't specify a MediaBox
@@ -119,7 +119,7 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
     cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0;
     haveCropBox = gFalse;
     rotate = 0;
-    resources.initNull();
+    resources.setToNull();
   }
 
   // media box
@@ -158,11 +158,10 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
   readBox(dict, "ArtBox", &artBox);
 
   // rotate
-  dict->lookup("Rotate", &obj1);
+  obj1 = dict->lookup("Rotate");
   if (obj1.isInt()) {
     rotate = obj1.getInt();
   }
-  obj1.free();
   while (rotate < 0) {
     rotate += 360;
   }
@@ -171,30 +170,21 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
   }
 
   // misc attributes
-  dict->lookup("LastModified", &lastModified);
-  dict->lookup("BoxColorInfo", &boxColorInfo);
-  dict->lookup("Group", &group);
-  dict->lookup("Metadata", &metadata);
-  dict->lookup("PieceInfo", &pieceInfo);
-  dict->lookup("SeparationInfo", &separationInfo);
+  lastModified = dict->lookup("LastModified");
+  boxColorInfo = dict->lookup("BoxColorInfo");
+  group = dict->lookup("Group");
+  metadata = dict->lookup("Metadata");
+  pieceInfo = dict->lookup("PieceInfo");
+  separationInfo = dict->lookup("SeparationInfo");
 
   // resource dictionary
-  dict->lookup("Resources", &obj1);
+  obj1 = dict->lookup("Resources");
   if (obj1.isDict()) {
-    resources.free();
-    obj1.copy(&resources);
+    resources = obj1.copy();
   }
-  obj1.free();
 }
 
 PageAttrs::~PageAttrs() {
-  lastModified.free();
-  boxColorInfo.free();
-  group.free();
-  metadata.free();
-  pieceInfo.free();
-  separationInfo.free();
-  resources.free();
 }
 
 void PageAttrs::clipBoxes() {
@@ -210,37 +200,33 @@ GBool PageAttrs::readBox(Dict *dict, const char *key, PDFRectangle *box) {
   Object obj1, obj2;
   GBool ok;
 
-  dict->lookup(key, &obj1);
+  obj1 = dict->lookup(key);
   if (obj1.isArray() && obj1.arrayGetLength() == 4) {
     ok = gTrue;
-    obj1.arrayGet(0, &obj2);
+    obj2 = obj1.arrayGet(0);
     if (obj2.isNum()) {
       tmp.x1 = obj2.getNum();
     } else {
       ok = gFalse;
     }
-    obj2.free();
-    obj1.arrayGet(1, &obj2);
+    obj2 = obj1.arrayGet(1);
     if (obj2.isNum()) {
       tmp.y1 = obj2.getNum();
     } else {
       ok = gFalse;
     }
-    obj2.free();
-    obj1.arrayGet(2, &obj2);
+    obj2 = obj1.arrayGet(2);
     if (obj2.isNum()) {
       tmp.x2 = obj2.getNum();
     } else {
       ok = gFalse;
     }
-    obj2.free();
-    obj1.arrayGet(3, &obj2);
+    obj2 = obj1.arrayGet(3);
     if (obj2.isNum()) {
       tmp.y2 = obj2.getNum();
     } else {
       ok = gFalse;
     }
-    obj2.free();
     if (tmp.x1 == 0 && tmp.x2 == 0 && tmp.y1 == 0 && tmp.y2 == 0)
       ok = gFalse;
     if (ok) {
@@ -255,7 +241,6 @@ GBool PageAttrs::readBox(Dict *dict, const char *key, PDFRectangle *box) {
   } else {
     ok = gFalse;
   }
-  obj1.free();
   return ok;
 }
 
@@ -264,8 +249,6 @@ GBool PageAttrs::readBox(Dict *dict, const char *key, PDFRectangle *box) {
 //------------------------------------------------------------------------
 
 Page::Page(PDFDoc *docA, int numA, Dict *pageDict, Ref pageRefA, PageAttrs *attrsA, Form *form) {
-  Object tmp;
-	
 #if MULTITHREADED
   gInitMutex(&mutex);
 #endif
@@ -276,7 +259,8 @@ Page::Page(PDFDoc *docA, int numA, Dict *pageDict, Ref pageRefA, PageAttrs *attr
   duration = -1;
   annots = NULL;
 
-  pageObj.initDict(pageDict);
+  pageDict->incRef();
+  pageObj = Object(pageDict);
   pageRef = pageRefA;
 
   // get attributes
@@ -284,79 +268,67 @@ Page::Page(PDFDoc *docA, int numA, Dict *pageDict, Ref pageRefA, PageAttrs *attr
   attrs->clipBoxes();
 
   // transtion
-  pageDict->lookupNF("Trans", &trans);
+  trans = pageDict->lookupNF("Trans");
   if (!(trans.isRef() || trans.isDict() || trans.isNull())) {
     error(errSyntaxError, -1, "Page transition object (page {0:d}) is wrong type ({1:s})",
 	  num, trans.getTypeName());
-    trans.free();
+    trans = Object();
   }
 
   // duration
-  pageDict->lookupNF("Dur", &tmp);
+  Object tmp = pageDict->lookupNF("Dur");
   if (!(tmp.isNum() || tmp.isNull())) {
     error(errSyntaxError, -1, "Page duration object (page {0:d}) is wrong type ({1:s})",
 	  num, tmp.getTypeName());
   } else if (tmp.isNum()) {
     duration = tmp.getNum();
   }
-  tmp.free();
 
   // annotations
-  pageDict->lookupNF("Annots", &annotsObj);
+  annotsObj = pageDict->lookupNF("Annots");
   if (!(annotsObj.isRef() || annotsObj.isArray() || annotsObj.isNull())) {
     error(errSyntaxError, -1, "Page annotations object (page {0:d}) is wrong type ({1:s})",
 	  num, annotsObj.getTypeName());
-    annotsObj.free();
     goto err2;
   }
 
   // contents
-  pageDict->lookupNF("Contents", &contents);
+  contents = pageDict->lookupNF("Contents");
   if (!(contents.isRef() || contents.isArray() ||
 	contents.isNull())) {
     error(errSyntaxError, -1, "Page contents object (page {0:d}) is wrong type ({1:s})",
 	  num, contents.getTypeName());
-    contents.free();
     goto err1;
   }
 
   // thumb
-  pageDict->lookupNF("Thumb", &thumb);
+  thumb = pageDict->lookupNF("Thumb");
   if (!(thumb.isStream() || thumb.isNull() || thumb.isRef())) {
       error(errSyntaxError, -1, "Page thumb object (page {0:d}) is wrong type ({1:s})",
             num, thumb.getTypeName());
-      thumb.free();
-      thumb.initNull(); 
+      thumb.setToNull();
   }
 
   // actions
-  pageDict->lookupNF("AA", &actions);
+  actions = pageDict->lookupNF("AA");
   if (!(actions.isDict() || actions.isNull())) {
       error(errSyntaxError, -1, "Page additional action object (page {0:d}) is wrong type ({1:s})",
             num, actions.getTypeName());
-      actions.free();
-      actions.initNull();
+      actions.setToNull();
   }
   
   return;
 
-  trans.initNull();
  err2:
-  annotsObj.initNull();
+  annotsObj.setToNull();
  err1:
-  contents.initNull();
+  contents.setToNull();
   ok = gFalse;
 }
 
 Page::~Page() {
   delete attrs;
   delete annots;
-  pageObj.free();
-  annotsObj.free();
-  contents.free();
-  trans.free();
-  thumb.free();
-  actions.free();
 #if MULTITHREADED
   gDestroyMutex(&mutex);
 #endif
@@ -366,6 +338,11 @@ Dict *Page::getResourceDict() {
   return attrs->getResourceDict();
 }
 
+Object *Page::getResourceDictObject()
+{
+  return attrs->getResourceDictObject();
+}
+
 Dict *Page::getResourceDictCopy(XRef *xrefA) { 
   pageLocker();
   Dict *dict = attrs->getResourceDict();
@@ -376,42 +353,32 @@ void Page::replaceXRef(XRef *xrefA) {
   Object obj1;
   Dict *pageDict = pageObj.getDict()->copy(xrefA);
   xref = xrefA;
-  trans.free();
-  pageDict->lookupNF("Trans", &trans);
-  annotsObj.free();
-  pageDict->lookupNF("Annots", &annotsObj);
-  contents.free();
-  pageDict->lookupNF("Contents", &contents);
+  trans = pageDict->lookupNF("Trans");
+  annotsObj = pageDict->lookupNF("Annots");
+  contents = pageDict->lookupNF("Contents");
   if (contents.isArray()) {
-    contents.free();
-    pageDict->lookupNF("Contents", &obj1)->getArray()->copy(xrefA, &contents);
-    obj1.free();
-  }
-  thumb.free();
-  pageDict->lookupNF("Thumb", &thumb);
-  actions.free();
-  pageDict->lookupNF("AA", &actions);
-  pageDict->lookup("Resources", &obj1);
+    obj1 = pageDict->lookupNF("Contents");
+    contents = obj1.getArray()->copy(xrefA);
+  }
+  thumb = pageDict->lookupNF("Thumb");
+  actions = pageDict->lookupNF("AA");
+  obj1 = pageDict->lookup("Resources");
   if (obj1.isDict()) {
-    attrs->replaceResource(&obj1);
+    attrs->replaceResource(std::move(obj1));
   }
-  obj1.free();
   delete pageDict;
 }
 
 Annots *Page::getAnnots(XRef *xrefA) {
   if (!annots) {
-    Object obj;
-    annots = new Annots(doc, num, getAnnots(&obj, (xrefA == NULL) ? xref : xrefA));
-    obj.free();
+    Object obj = getAnnotsObject(xrefA);
+    annots = new Annots(doc, num, &obj);
   }
 
   return annots;
 }
 
 void Page::addAnnot(Annot *annot) {
-  Object obj1;
-  Object tmp;
   Ref annotRef = annot->getRef ();
 
   // Make sure we have annots before adding the new one
@@ -425,24 +392,22 @@ void Page::addAnnot(Annot *annot) {
     // page doesn't have annots array,
     // we have to create it
 
-    obj1.initArray(xref);
-    obj1.arrayAdd(tmp.initRef (annotRef.num, annotRef.gen));
-    tmp.free();
+    Object obj1 = Object(new Array(xref));
+    obj1.arrayAdd(Object(annotRef.num, annotRef.gen));
 
     annotsRef = xref->addIndirectObject (&obj1);
-    annotsObj.initRef(annotsRef.num, annotsRef.gen);
-    pageObj.dictSet ("Annots", &annotsObj);
+    annotsObj = Object(annotsRef.num, annotsRef.gen);
+    pageObj.dictSet ("Annots", Object(annotsRef.num, annotsRef.gen));
     xref->setModifiedObject (&pageObj, pageRef);
   } else {
-    getAnnots(&obj1);
+    Object obj1 = getAnnotsObject();
     if (obj1.isArray()) {
-      obj1.arrayAdd (tmp.initRef (annotRef.num, annotRef.gen));
+      obj1.arrayAdd (Object(annotRef.num, annotRef.gen));
       if (annotsObj.isRef())
         xref->setModifiedObject (&obj1, annotsObj.getRef());
       else
         xref->setModifiedObject (&pageObj, pageRef);
     }
-    obj1.free();
   }
 
   // Popup annots are already handled by markup annots,
@@ -464,27 +429,24 @@ void Page::addAnnot(Annot *annot) {
 
 void Page::removeAnnot(Annot *annot) {
   Ref annotRef = annot->getRef();
-  Object annArray;
 
   pageLocker();
-  getAnnots(&annArray);
+  Object annArray = getAnnotsObject();
   if (annArray.isArray()) {
     int idx = -1;
     // Get annotation position
     for (int i = 0; idx == -1 && i < annArray.arrayGetLength(); ++i) {
-      Object tmp;
-      if (annArray.arrayGetNF(i, &tmp)->isRef()) {
+      Object tmp = annArray.arrayGetNF(i);
+      if (tmp.isRef()) {
         Ref currAnnot = tmp.getRef();
         if (currAnnot.num == annotRef.num && currAnnot.gen == annotRef.gen) {
           idx = i;
         }
       }
-      tmp.free();
     }
 
     if (idx == -1) {
       error(errInternal, -1, "Annotation doesn't belong to this page");
-      annArray.free();
       return;
     }
     annots->removeAnnot(annot); // Gracefully fails on popup windows
@@ -497,7 +459,6 @@ void Page::removeAnnot(Annot *annot) {
       xref->setModifiedObject (&pageObj, pageRef);
     }
   }
-  annArray.free();
   annot->removeReferencedObjects(); // Note: Might recurse in removeAnnot again
   annot->setPage(0, gFalse);
 }
@@ -573,7 +534,6 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
                         void *annotDisplayDecideCbkData,
                         GBool copyXRef) {
   Gfx *gfx;
-  Object obj;
   Annots *annotList;
   int i;
   
@@ -595,7 +555,7 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
 		  printing,
 		  abortCheckCbk, abortCheckCbkData, localXRef);
 
-  contents.fetch(localXRef, &obj);
+  Object obj = contents.fetch(localXRef);
   if (!obj.isNull()) {
     gfx->saveState();
     gfx->display(&obj);
@@ -605,7 +565,6 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
     // OutputDev
     out->dump();
   }
-  obj.free();
 
   // draw annotations
   annotList = getAnnots();
@@ -633,15 +592,12 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
 }
 
 void Page::display(Gfx *gfx) {
-  Object obj;
-
-  contents.fetch(xref, &obj);
+  Object obj = contents.fetch(xref);
   if (!obj.isNull()) {
     gfx->saveState();
     gfx->display(&obj);
     gfx->restoreState();
   }
-  obj.free();
 }
 
 GBool Page::loadThumb(unsigned char **data_out,
@@ -650,7 +606,7 @@ GBool Page::loadThumb(unsigned char **data_out,
 {
   unsigned int pixbufdatasize;
   int width, height, bits;
-  Object obj1, fetched_thumb;
+  Object obj1;
   Dict *dict;
   GfxColorSpace *colorSpace;
   GBool success = gFalse;
@@ -659,9 +615,8 @@ GBool Page::loadThumb(unsigned char **data_out,
 
   /* Get stream dict */
   pageLocker();
-  thumb.fetch(xref, &fetched_thumb);
+  Object fetched_thumb = thumb.fetch(xref);
   if (!fetched_thumb.isStream()) {
-    fetched_thumb.free();
     return gFalse;
   }
 
@@ -683,25 +638,21 @@ GBool Page::loadThumb(unsigned char **data_out,
   pixbufdatasize = width * height * 3;
 
   /* Get color space */
-  dict->lookup ("ColorSpace", &obj1);
+  obj1 = dict->lookup ("ColorSpace");
   if (obj1.isNull ()) {
-    obj1.free ();
-    dict->lookup ("CS", &obj1);
+    obj1 = dict->lookup ("CS");
   }
   colorSpace = GfxColorSpace::parse(NULL, &obj1, NULL, NULL);
-  obj1.free();
   if (!colorSpace) {
     fprintf (stderr, "Error: Cannot parse color space\n");
     goto fail1;
   }
 
-  dict->lookup("Decode", &obj1);
+  obj1 = dict->lookup("Decode");
   if (obj1.isNull()) {
-    obj1.free();
-    dict->lookup("D", &obj1);
+    obj1 = dict->lookup("D");
   }
   colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
-  obj1.free();
   if (!colorMap->isOk()) {
     fprintf (stderr, "Error: invalid colormap\n");
     delete colorMap;
@@ -744,8 +695,6 @@ GBool Page::loadThumb(unsigned char **data_out,
 
   delete colorMap;
  fail1:
-  fetched_thumb.free();
-
   return success;
 }
 
@@ -842,21 +791,16 @@ void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI,
 }
 
 LinkAction* Page::getAdditionalAction(PageAdditionalActionsType type) {
-  Object additionalActionsObject;
-  LinkAction *linkAction = NULL;
-
-  if (actions.fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
+  LinkAction *linkAction = nullptr;
+  Object additionalActionsObject = actions.fetch(doc->getXRef());
+  if (additionalActionsObject.isDict()) {
     const char *key = (type == actionOpenPage ?  "O" :
                        type == actionClosePage ? "C" : NULL);
 
-    Object actionObject;
-
-    if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
+    Object actionObject = additionalActionsObject.dictLookup(key);
+    if (actionObject.isDict())
       linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
-    actionObject.free();
   }
 
-  additionalActionsObject.free();
-
   return linkAction;
 }
diff --git a/poppler/Page.h b/poppler/Page.h
index 7a20b55c..e548c867 100644
--- a/poppler/Page.h
+++ b/poppler/Page.h
@@ -107,8 +107,10 @@ public:
 	? separationInfo.getDict() : (Dict *)NULL; }
   Dict *getResourceDict()
     { return resources.isDict() ? resources.getDict() : (Dict *)NULL; }
-  void replaceResource(Object *obj1)
-  {  obj1->shallowCopy(&resources); }
+  Object *getResourceDictObject()
+    { return &resources; }
+  void replaceResource(Object &&obj1)
+  {  resources = std::move(obj1); }
 
   // Clip all other boxes to the MediaBox.
   void clipBoxes();
@@ -177,10 +179,11 @@ public:
 
   // Get resource dictionary.
   Dict *getResourceDict();
+  Object *getResourceDictObject();
   Dict *getResourceDictCopy(XRef *xrefA);
 
   // Get annotations array.
-  Object *getAnnots(Object *obj, XRef *xrefA = NULL) { return annotsObj.fetch((xrefA == NULL) ? xref : xrefA, obj); }
+  Object getAnnotsObject(XRef *xrefA = nullptr) { return annotsObj.fetch(xrefA ? xrefA : xref); }
   // Add a new annotation to the page
   void addAnnot(Annot *annot);
   // Remove an existing annotation from the page
@@ -193,14 +196,14 @@ public:
   Annots *getAnnots(XRef *xrefA = NULL);
 
   // Get contents.
-  Object *getContents(Object *obj) { return contents.fetch(xref, obj); }
+  Object getContents() { return contents.fetch(xref); }
 
   // Get thumb.
-  Object *getThumb(Object *obj) { return thumb.fetch(xref, obj); }
+  Object getThumb() { return thumb.fetch(xref); }
   GBool loadThumb(unsigned char **data, int *width, int *height, int *rowstride);
 
   // Get transition.
-  Object *getTrans(Object *obj) { return trans.fetch(xref, obj); }
+  Object getTrans() { return trans.fetch(xref); }
 
   // Get form.
   FormPageWidgets *getFormWidgets();
@@ -211,7 +214,7 @@ public:
   double getDuration() { return duration; }
 
   // Get actions
-  Object *getActions(Object *obj) { return actions.fetch(xref, obj); }
+  Object getActions() { return actions.fetch(xref); }
 
   enum PageAdditionalActionsType {
     actionOpenPage,     ///< Performed when opening the page
diff --git a/poppler/PageLabelInfo.cc b/poppler/PageLabelInfo.cc
index 3153377f..ad851914 100644
--- a/poppler/PageLabelInfo.cc
+++ b/poppler/PageLabelInfo.cc
@@ -22,10 +22,9 @@
 #include "PageLabelInfo_p.h"
 
 PageLabelInfo::Interval::Interval(Object *dict, int baseA) {
-  Object obj;
-
   style = None;
-  if (dict->dictLookup("S", &obj)->isName()) {
+  Object obj = dict->dictLookup("S");
+  if (obj.isName()) {
     if (obj.isName("D")) {
       style = Arabic;
     } else if (obj.isName("R")) {
@@ -38,19 +37,18 @@ PageLabelInfo::Interval::Interval(Object *dict, int baseA) {
       style = LowercaseLatin;
     }
   }
-  obj.free();
 
-  if (dict->dictLookup("P", &obj)->isString())
+  obj = dict->dictLookup("P");
+  if (obj.isString())
     prefix = obj.getString()->copy();
   else
     prefix = new GooString("");
-  obj.free();
 
-  if (dict->dictLookup("St", &obj)->isInt())
+  obj = dict->dictLookup("St");
+  if (obj.isInt())
     first = obj.getInt();
   else
     first = 1;
-  obj.free();
 
   base = baseA;
 }
@@ -86,40 +84,32 @@ PageLabelInfo::~PageLabelInfo() {
 }
 
 void PageLabelInfo::parse(Object *tree) {
-  Object nums, obj;
-  Object kids, kid, limits, low, high;
-  int i, base;
-  Interval *interval;
-
   // leaf node
-  if (tree->dictLookup("Nums", &nums)->isArray()) {
-    for (i = 0; i < nums.arrayGetLength(); i += 2) {
-      if (!nums.arrayGet(i, &obj)->isInt()) {
-	obj.free();
+  Object nums = tree->dictLookup("Nums");
+  if (nums.isArray()) {
+    for (int i = 0; i < nums.arrayGetLength(); i += 2) {
+      Object obj = nums.arrayGet(i);
+      if (!obj.isInt()) {
 	continue;
       }
-      base = obj.getInt();
-      obj.free();
-      if (!nums.arrayGet(i + 1, &obj)->isDict()) {
-	obj.free();
+      int base = obj.getInt();
+      obj = nums.arrayGet(i + 1);
+      if (!obj.isDict()) {
 	continue;
       }
 
-      interval = new Interval(&obj, base);
-      obj.free();
-      intervals.append(interval);
+      intervals.append(new Interval(&obj, base));
     }
   }
-  nums.free();
 
-  if (tree->dictLookup("Kids", &kids)->isArray()) {
-    for (i = 0; i < kids.arrayGetLength(); ++i) {
-      if (kids.arrayGet(i, &kid)->isDict())
+  Object kids = tree->dictLookup("Kids");
+  if (kids.isArray()) {
+    for (int i = 0; i < kids.arrayGetLength(); ++i) {
+      Object kid = kids.arrayGet(i);
+      if (kid.isDict())
 	parse(&kid);
-      kid.free();
     }
   }
-  kids.free();
 }
 
 GBool PageLabelInfo::labelToIndex(GooString *label, int *index)
diff --git a/poppler/PageTransition.cc b/poppler/PageTransition.cc
index d5a84f89..ff340881 100644
--- a/poppler/PageTransition.cc
+++ b/poppler/PageTransition.cc
@@ -50,7 +50,8 @@ PageTransition::PageTransition (Object *trans) {
   dict = trans->getDict();
 
   // get type
-  if (dict->lookup("S", &obj)->isName()) {
+  obj = dict->lookup("S");
+  if (obj.isName()) {
     const char *s = obj.getName();
     
     if (strcmp("R", s) == 0)
@@ -78,16 +79,16 @@ PageTransition::PageTransition (Object *trans) {
     else if (strcmp("Fade", s) == 0)
       type = transitionFade;
   }
-  obj.free();
 
   // get duration
-  if (dict->lookup("D", &obj)->isNum()) {
+  obj = dict->lookup("D");
+  if (obj.isNum()) {
     duration = obj.getNum();
   }
-  obj.free();
 
   // get alignment
-  if (dict->lookup("Dm", &obj)->isName()) {
+  obj = dict->lookup("Dm");
+  if (obj.isName()) {
     const char *dm = obj.getName();
     
     if (strcmp("H", dm) == 0)
@@ -95,10 +96,10 @@ PageTransition::PageTransition (Object *trans) {
     else if (strcmp("V", dm) == 0)
       alignment = transitionVertical;
   }
-  obj.free();
 
   // get direction
-  if (dict->lookup("M", &obj)->isName()) {
+  obj = dict->lookup("M");
+  if (obj.isName()) {
     const char *m = obj.getName();
     
     if (strcmp("I", m) == 0)
@@ -106,31 +107,30 @@ PageTransition::PageTransition (Object *trans) {
     else if (strcmp("O", m) == 0)
       direction = transitionOutward;
   }
-  obj.free();
 
   // get angle
-  if (dict->lookup("Di", &obj)->isInt()) {
+  obj = dict->lookup("Di");
+  if (obj.isInt()) {
     angle = obj.getInt();
   }
-  obj.free();
 
-  if (dict->lookup("Di", &obj)->isName()) {
+  obj = dict->lookup("Di");
+  if (obj.isName()) {
     if (strcmp("None", obj.getName()) == 0)
       angle = 0;
   }
-  obj.free();
 
   // get scale
-  if (dict->lookup("SS", &obj)->isNum()) {
+  obj = dict->lookup("SS");
+  if (obj.isNum()) {
     scale = obj.getNum();
   }
-  obj.free();
 
   // get rectangular
-  if (dict->lookup("B", &obj)->isBool()) {
+  obj = dict->lookup("B");
+  if (obj.isBool()) {
     rectangular = obj.getBool();
   }
-  obj.free();
 }
 
 PageTransition::~PageTransition()
diff --git a/poppler/Parser.cc b/poppler/Parser.cc
index 1be2e9f7..6e71354a 100644
--- a/poppler/Parser.cc
+++ b/poppler/Parser.cc
@@ -50,50 +50,46 @@ Parser::Parser(XRef *xrefA, Lexer *lexerA, GBool allowStreamsA) {
   lexer = lexerA;
   inlineImg = 0;
   allowStreams = allowStreamsA;
-  lexer->getObj(&buf1);
-  lexer->getObj(&buf2);
+  buf1 = lexer->getObj();
+  buf2 = lexer->getObj();
 }
 
 Parser::~Parser() {
-  buf1.free();
-  buf2.free();
   delete lexer;
 }
 
-Object *Parser::getObj(Object *obj, int recursion)
+Object Parser::getObj(int recursion)
 {
-  return getObj(obj, gFalse, NULL, cryptRC4, 0, 0, 0, recursion);
+  return getObj(gFalse, NULL, cryptRC4, 0, 0, 0, recursion);
 }
 
-Object *Parser::getObj(Object *obj, GBool simpleOnly,
+Object Parser::getObj(GBool simpleOnly,
            Guchar *fileKey,
 		       CryptAlgorithm encAlgorithm, int keyLength,
 		       int objNum, int objGen, int recursion,
 		       GBool strict) {
+  Object obj;
   char *key;
   Stream *str;
-  Object obj2;
-  int num;
   DecryptStream *decrypt;
   GooString *s, *s2;
   int c;
 
   // refill buffer after inline image data
   if (inlineImg == 2) {
-    buf1.free();
-    buf2.free();
-    lexer->getObj(&buf1);
-    lexer->getObj(&buf2);
+    buf1 = lexer->getObj();
+    buf2 = lexer->getObj();
     inlineImg = 0;
   }
 
   // array
   if (!simpleOnly && likely(recursion < recursionLimit) && buf1.isCmd("[")) {
     shift();
-    obj->initArray(xref);
-    while (!buf1.isCmd("]") && !buf1.isEOF())
-      obj->arrayAdd(getObj(&obj2, gFalse, fileKey, encAlgorithm, keyLength,
-			   objNum, objGen, recursion + 1));
+    obj = Object(new Array(xref));
+    while (!buf1.isCmd("]") && !buf1.isEOF()) {
+      Object obj2 = getObj(gFalse, fileKey, encAlgorithm, keyLength, objNum, objGen, recursion + 1);
+      obj.arrayAdd(std::move(obj2));
+    }
     if (buf1.isEOF()) {
       error(errSyntaxError, getPos(), "End of file inside array");
       if (strict) goto err;
@@ -103,7 +99,7 @@ Object *Parser::getObj(Object *obj, GBool simpleOnly,
   // dictionary or stream
   } else if (!simpleOnly && likely(recursion < recursionLimit) && buf1.isCmd("<<")) {
     shift(objNum);
-    obj->initDict(xref);
+    obj = Object(new Dict(xref));
     while (!buf1.isCmd(">>") && !buf1.isEOF()) {
       if (!buf1.isName()) {
 	error(errSyntaxError, getPos(), "Dictionary key must be a name object");
@@ -118,7 +114,8 @@ Object *Parser::getObj(Object *obj, GBool simpleOnly,
 	  if (strict && buf1.isError()) goto err;
 	  break;
 	}
-	obj->dictAdd(key, getObj(&obj2, gFalse, fileKey, encAlgorithm, keyLength, objNum, objGen, recursion + 1));
+	Object obj2 = getObj(gFalse, fileKey, encAlgorithm, keyLength, objNum, objGen, recursion + 1);
+	obj.dictAdd(key, std::move(obj2));
       }
     }
     if (buf1.isEOF()) {
@@ -128,13 +125,12 @@ Object *Parser::getObj(Object *obj, GBool simpleOnly,
     // stream objects are not allowed inside content streams or
     // object streams
     if (buf2.isCmd("stream")) {
-      if (allowStreams && (str = makeStream(obj, fileKey, encAlgorithm, keyLength,
+      if (allowStreams && (str = makeStream(std::move(obj), fileKey, encAlgorithm, keyLength,
                                             objNum, objGen, recursion + 1,
                                             strict))) {
-        obj->initStream(str);
+        return Object(str);
       } else {
-        obj->free();
-        obj->initError();
+        return Object(objError);
       }
     } else {
       shift();
@@ -142,23 +138,22 @@ Object *Parser::getObj(Object *obj, GBool simpleOnly,
 
   // indirect reference or integer
   } else if (buf1.isInt()) {
-    num = buf1.getInt();
+    const int num = buf1.getInt();
     shift();
     if (buf1.isInt() && buf2.isCmd("R")) {
-      obj->initRef(num, buf1.getInt());
+      const int gen = buf1.getInt();
       shift();
       shift();
+      return Object(num, gen);
     } else {
-      obj->initInt(num);
+      return Object(num);
     }
 
   // string
   } else if (buf1.isString() && fileKey) {
     s = buf1.getString();
     s2 = new GooString();
-    obj2.initNull();
-    decrypt = new DecryptStream(new MemStream(s->getCString(), 0,
-					      s->getLength(), &obj2),
+    decrypt = new DecryptStream(new MemStream(s->getCString(), 0, s->getLength(), Object(objNull)),
 				fileKey, encAlgorithm, keyLength,
 				objNum, objGen);
     decrypt->reset();
@@ -166,7 +161,7 @@ Object *Parser::getObj(Object *obj, GBool simpleOnly,
       s2->append((char)c);
     }
     delete decrypt;
-    obj->initString(s2);
+    obj = Object(s2);
     shift();
 
   // simple object
@@ -174,25 +169,20 @@ Object *Parser::getObj(Object *obj, GBool simpleOnly,
     // avoid re-allocating memory for complex objects like strings by
     // shallow copy of <buf1> to <obj> and nulling <buf1> so that
     // subsequent buf1.free() won't free this memory
-    buf1.shallowCopy(obj);
-    buf1.initNull();
+    obj = std::move(buf1);
     shift();
   }
 
   return obj;
 
 err:
-  obj->free();
-  obj->initError();
-  return obj;
-
+  return Object(objError);
 }
 
-Stream *Parser::makeStream(Object *dict, Guchar *fileKey,
+Stream *Parser::makeStream(Object &&dict, Guchar *fileKey,
 			   CryptAlgorithm encAlgorithm, int keyLength,
 			   int objNum, int objGen, int recursion,
                            GBool strict) {
-  Object obj;
   BaseStream *baseStr;
   Stream *str;
   Goffset length;
@@ -206,16 +196,13 @@ Stream *Parser::makeStream(Object *dict, Guchar *fileKey,
   pos = str->getPos();
 
   // get length
-  dict->dictLookup("Length", &obj, recursion);
+  Object obj = dict.dictLookup("Length", recursion);
   if (obj.isInt()) {
     length = obj.getInt();
-    obj.free();
   } else if (obj.isInt64()) {
     length = obj.getInt64();
-    obj.free();
   } else {
     error(errSyntaxError, getPos(), "Bad 'Length' attribute in stream");
-    obj.free();
     if (strict) return NULL;
     length = 0;
   }
@@ -252,9 +239,7 @@ Stream *Parser::makeStream(Object *dict, Guchar *fileKey,
       // shift until we find the proper endstream or we change to another object or reach eof
       length = lexer->getPos() - pos;
       if (buf1.isCmd("endstream")) {
-        obj.initInt64(length);
-        dict->dictSet("Length", &obj);
-        obj.free();
+        dict.dictSet("Length", Object(length));
       }
     } else {
       // When building the xref we can't use it so use this
@@ -265,7 +250,7 @@ Stream *Parser::makeStream(Object *dict, Guchar *fileKey,
   }
 
   // make base stream
-  str = baseStr->makeSubStream(pos, gTrue, length, dict);
+  str = baseStr->makeSubStream(pos, gTrue, length, std::move(dict));
 
   // handle decryption
   if (fileKey) {
@@ -292,12 +277,12 @@ void Parser::shift(int objNum) {
     lexer->skipChar();		// skip char after 'ID' command
     inlineImg = 1;
   }
-  buf1.free();
-  buf2.shallowCopy(&buf1);
+  buf1 = std::move(buf2);
   if (inlineImg > 0)		// don't buffer inline image data
-    buf2.initNull();
-  else
-    lexer->getObj(&buf2, objNum);
+    buf2.setToNull();
+  else {
+    buf2 = lexer->getObj(objNum);
+  }
 }
 
 void Parser::shift(const char *cmdA, int objNum) {
@@ -313,13 +298,12 @@ void Parser::shift(const char *cmdA, int objNum) {
     lexer->skipChar();		// skip char after 'ID' command
     inlineImg = 1;
   }
-  buf1.free();
-  buf2.shallowCopy(&buf1);
+  buf1 = std::move(buf2);
   if (inlineImg > 0) {
-    buf2.initNull();
+    buf2.setToNull();
   } else if (buf1.isCmd(cmdA)) {
-    lexer->getObj(&buf2, objNum);
+    buf2 = lexer->getObj(objNum);
   } else {
-    lexer->getObj(&buf2, cmdA, objNum);
+    buf2 = lexer->getObj(cmdA, objNum);
   }
 }
diff --git a/poppler/Parser.h b/poppler/Parser.h
index 1ce9445e..2d9acdf6 100644
--- a/poppler/Parser.h
+++ b/poppler/Parser.h
@@ -48,13 +48,14 @@ public:
   // Get the next object from the input stream.  If <simpleOnly> is
   // true, do not parse compound objects (arrays, dictionaries, or
   // streams).
-  Object *getObj(Object *obj, GBool simpleOnly = gFalse, 
+  Object getObj(GBool simpleOnly = gFalse,
      Guchar *fileKey = NULL,
 		 CryptAlgorithm encAlgorithm = cryptRC4, int keyLength = 0,
 		 int objNum = 0, int objGen = 0, int recursion = 0,
 		 GBool strict = gFalse);
   
-  Object *getObj(Object *obj, int recursion);
+  Object getObj(int recursion);
+  template<typename T> Object getObj(T) = delete;
 
   // Get stream.
   Stream *getStream() { return lexer->getStream(); }
@@ -70,7 +71,7 @@ private:
   Object buf1, buf2;		// next two tokens
   int inlineImg;		// set when inline image data is encountered
 
-  Stream *makeStream(Object *dict, Guchar *fileKey,
+  Stream *makeStream(Object &&dict, Guchar *fileKey,
 		     CryptAlgorithm encAlgorithm, int keyLength,
 		     int objNum, int objGen, int recursion,
 		     GBool strict);
diff --git a/poppler/PopplerCache.cc b/poppler/PopplerCache.cc
index 970c003e..d9d07d00 100644
--- a/poppler/PopplerCache.cc
+++ b/poppler/PopplerCache.cc
@@ -121,14 +121,9 @@ class ObjectKey : public PopplerCacheKey {
 
 class ObjectItem : public PopplerCacheItem {
   public:
-    ObjectItem(Object *obj)
+    ObjectItem(Object &&obj)
     {
-      obj->copy(&item);
-    }
-
-    ~ObjectItem()
-    {
-      item.free();
+      item = std::move(obj);
     }
 
     Object item;
@@ -144,20 +139,18 @@ PopplerObjectCache::~PopplerObjectCache() {
 }
 
 Object *PopplerObjectCache::put(const Ref &ref) {
-  Object obj;
-  xref->fetch(ref.num, ref.gen, &obj);
+  Object obj = xref->fetch(ref.num, ref.gen);
 
   ObjectKey *key = new ObjectKey(ref.num, ref.gen);
-  ObjectItem *item = new ObjectItem(&obj);
+  ObjectItem *item = new ObjectItem(std::move(obj));
   cache->put(key, item);
-  obj.free();
 
   return &item->item;
 }
 
-Object *PopplerObjectCache::lookup(const Ref &ref, Object *obj) {
+Object PopplerObjectCache::lookup(const Ref &ref) {
   ObjectKey key(ref.num, ref.gen);
   ObjectItem *item = static_cast<ObjectItem *>(cache->lookup(key));
 
-  return item ? item->item.copy(obj) : obj->initNull();
+  return item ? item->item.copy() : Object(objNull);
 }
diff --git a/poppler/PopplerCache.h b/poppler/PopplerCache.h
index 74010a2f..73545384 100644
--- a/poppler/PopplerCache.h
+++ b/poppler/PopplerCache.h
@@ -68,7 +68,7 @@ class PopplerObjectCache
     ~PopplerObjectCache();
 
     Object *put(const Ref &ref);
-    Object *lookup(const Ref &ref, Object *obj);
+    Object lookup(const Ref &ref);
 
   private:
     XRef *xref;
diff --git a/poppler/Rendition.cc b/poppler/Rendition.cc
index c040bf2b..4063639b 100644
--- a/poppler/Rendition.cc
+++ b/poppler/Rendition.cc
@@ -44,26 +44,26 @@ MediaWindowParameters::~MediaWindowParameters() {
 }
 
 void MediaWindowParameters::parseFWParams(Object* obj) {
-  Object tmp;
-
-  if (obj->dictLookup("D", &tmp)->isArray()) {
+  Object tmp = obj->dictLookup("D");
+  if (tmp.isArray()) {
     Array * dim = tmp.getArray();
     
     if (dim->getLength() >= 2) {
-      Object dd;
-      if (dim->get(0, &dd)->isInt()) {
+      Object dd = dim->get(0);
+      if (dd.isInt()) {
 	width = dd.getInt();
       }
-      dd.free();
-      if (dim->get(1, &dd)->isInt()) {
+
+      dd = dim->get(1);
+      if (dd.isInt()) {
 	height = dd.getInt();
       }
-      dd.free();
+
     }
   }
-  tmp.free();
 
-  if (obj->dictLookup("RT", &tmp)->isInt()) {
+  tmp = obj->dictLookup("RT");
+  if (tmp.isInt()) {
     int t = tmp.getInt();
     switch(t) {
     case 0: relativeTo = windowRelativeToDocument; break;
@@ -71,9 +71,9 @@ void MediaWindowParameters::parseFWParams(Object* obj) {
     case 2: relativeTo = windowRelativeToDesktop; break;
     }
   }
-  tmp.free();
 
-  if (obj->dictLookup("P",&tmp)->isInt()) {
+  tmp = obj->dictLookup("P");
+  if (tmp.isInt()) {
     int t = tmp.getInt();
 
     switch(t) {
@@ -115,21 +115,19 @@ void MediaWindowParameters::parseFWParams(Object* obj) {
       break;
     }
   }
-  tmp.free();
 
-  if (obj->dictLookup("T", &tmp)->isBool()) {
+  tmp = obj->dictLookup("T");
+  if (tmp.isBool()) {
     hasTitleBar = tmp.getBool();
   }
-  tmp.free();
-  if (obj->dictLookup("UC", &tmp)->isBool()) {
+  tmp = obj->dictLookup("UC");
+  if (tmp.isBool()) {
     hasCloseButton = tmp.getBool();
   }
-  tmp.free();
-  if (obj->dictLookup("R", &tmp)->isInt()) {
+  tmp = obj->dictLookup("R");
+  if (tmp.isInt()) {
     isResizeable = (tmp.getInt() != 0);
   }
-  tmp.free();
-
 }
 
 MediaParameters::MediaParameters() {
@@ -148,20 +146,18 @@ MediaParameters::~MediaParameters() {
 }
 
 void MediaParameters::parseMediaPlayParameters(Object* obj) {
-  
-  Object tmp;
-
-  if (obj->dictLookup("V", &tmp)->isInt()) {
+  Object tmp = obj->dictLookup("V");
+  if (tmp.isInt()) {
     volume = tmp.getInt();
   }
-  tmp.free();
 
-  if (obj->dictLookup("C", &tmp)->isBool()) {
+  tmp = obj->dictLookup("C");
+  if (tmp.isBool()) {
     showControls = tmp.getBool();
   }
-  tmp.free();
 
-  if (obj->dictLookup("F", &tmp)->isInt()) {
+  tmp = obj->dictLookup("F");
+  if (tmp.isInt()) {
     int t = tmp.getInt();
     
     switch(t) {
@@ -173,47 +169,42 @@ void MediaParameters::parseMediaPlayParameters(Object* obj) {
     case 5: fittingPolicy = fittingUndefined; break;
     }
   }
-  tmp.free();
 
   // duration parsing
   // duration's default value is set to 0, which means : intrinsinc media duration
-  if (obj->dictLookup("D", &tmp)->isDict()) {
-    Object oname, ddict, tmp2;
-    if (tmp.dictLookup("S", &oname)->isName()) {
+  tmp = obj->dictLookup("D");
+  if (tmp.isDict()) {
+    Object oname = tmp.dictLookup("S");
+    if (oname.isName()) {
       char* name = oname.getName();
       if (!strcmp(name, "F"))
 	duration = -1; // infinity
       else if (!strcmp(name, "T")) {
-	if (tmp.dictLookup("T", &ddict)->isDict()) {
-	  if (ddict.dictLookup("V", &tmp2)->isNum()) {
+	Object ddict = tmp.dictLookup("T");
+	if (ddict.isDict()) {
+	  Object tmp2 = ddict.dictLookup("V");
+	  if (tmp2.isNum()) {
 	    duration = Gulong(tmp2.getNum());
 	  }
-	  tmp2.free();
 	}
-	ddict.free();
       }
     }
-    oname.free();
   }
-  tmp.free();
 
-
-  if (obj->dictLookup("A", &tmp)->isBool()) {
+  tmp = obj->dictLookup("A");
+  if (tmp.isBool()) {
     autoPlay = tmp.getBool();
   }
-  tmp.free();
 
-  if (obj->dictLookup("RC", &tmp)->isNum()) {
+  tmp = obj->dictLookup("RC");
+  if (tmp.isNum()) {
     repeatCount = tmp.getNum();
   }
-  tmp.free();
-
 }
 
 void MediaParameters::parseMediaScreenParameters(Object* obj) {
-  Object tmp;
-
-  if (obj->dictLookup("W", &tmp)->isInt()) {
+  Object tmp = obj->dictLookup("W");
+  if (tmp.isInt()) {
     int t = tmp.getInt();
     
     switch(t) {
@@ -223,41 +214,33 @@ void MediaParameters::parseMediaScreenParameters(Object* obj) {
     case 3: windowParams.type = MediaWindowParameters::windowEmbedded; break;
     }
   }
-  tmp.free();
 
   // background color
-  if (obj->dictLookup("B", &tmp)->isArray()) {
+  tmp = obj->dictLookup("B");
+  if (tmp.isArray()) {
     Array* color = tmp.getArray();
 
-    Object component;
-    
-    color->get(0, &component);
+    Object component = color->get(0);
     bgColor.r = component.getNum();
-    component.free();
 
-    color->get(1, &component);
+    component = color->get(1);
     bgColor.g = component.getNum();
-    component.free();
 
-    color->get(2, &component);
+    component = color->get(2);
     bgColor.b = component.getNum();
-    component.free();
   }
-  tmp.free();
-
 
   // opacity
-  if (obj->dictLookup("O", &tmp)->isNum()) {
+  tmp = obj->dictLookup("O");
+  if (tmp.isNum()) {
     opacity = tmp.getNum();
   }
-  tmp.free();
 
   if (windowParams.type == MediaWindowParameters::windowFloating) {
-    Object winDict;
-    if (obj->dictLookup("F",&winDict)->isDict()) {
+    Object winDict = obj->dictLookup("F");
+    if (winDict.isDict()) {
       windowParams.parseFWParams(&winDict);
     }
-    winDict.free();
   }
 }
 
@@ -273,7 +256,6 @@ MediaRendition::~MediaRendition() {
 }
 
 MediaRendition::MediaRendition(Object* obj) {
-  Object tmp, tmp2;
   GBool hasClip = gFalse;
 
   ok = gTrue;
@@ -285,40 +267,40 @@ MediaRendition::MediaRendition(Object* obj) {
   //
   // Parse media clip data
   //
-  if (obj->dictLookup("C", &tmp2)->isDict()) { // media clip
+  Object tmp2 = obj->dictLookup("C");
+  if (tmp2.isDict()) { // media clip
     hasClip = gTrue;
-    if (tmp2.dictLookup("S", &tmp)->isName()) {
+    Object tmp = tmp2.dictLookup("S");
+    if (tmp.isName()) {
       if (!strcmp(tmp.getName(), "MCD")) { // media clip data
-        Object obj1, obj2;
-	if (tmp2.dictLookup("D", &obj1)->isDict()) {
-	  if (obj1.dictLookup("F", &obj2)->isString()) {
+        Object obj1 = tmp2.dictLookup("D");
+	if (obj1.isDict()) {
+	  Object obj2 = obj1.dictLookup("F");
+	  if (obj2.isString()) {
 	    fileName = obj2.getString()->copy();
 	  }
-	  obj2.free();
-	  if (obj1.dictLookup("EF", &obj2)->isDict()) {
-	    Object embedded;
-	    if (obj2.dictLookup("F", &embedded)->isStream()) {
+	  obj2 = obj1.dictLookup("EF");
+	  if (obj2.isDict()) {
+	    Object embedded = obj2.dictLookup("F");
+	    if (embedded.isStream()) {
 	      isEmbedded = gTrue;
 	      embeddedStream = embedded.getStream();
 	      // "copy" stream
 	      embeddedStream->incRef();
 	    }
-	    embedded.free();
 	  }
-	  obj2.free();
 
 	  // TODO: D might be a form XObject too
 	} else {
 	  error (errSyntaxError, -1, "Invalid Media Clip Data");
 	  ok = gFalse;
 	}
-	obj1.free();
 
 	// FIXME: ignore CT if D is a form XObject
-	if (tmp2.dictLookup("CT", &obj1)->isString()) {
+	obj1 = tmp2.dictLookup("CT");
+	if (obj1.isString()) {
 	  contentType = obj1.getString()->copy();
 	}
-	obj1.free();
       } else if (!strcmp(tmp.getName(), "MCS")) { // media clip data
         // TODO
       }
@@ -326,45 +308,41 @@ MediaRendition::MediaRendition(Object* obj) {
       error (errSyntaxError, -1, "Invalid Media Clip");
       ok = gFalse;
     }
-    tmp.free();
   }
-  tmp2.free();
 
   if (!ok)
     return;
 
   //
   // parse Media Play Parameters
-  if (obj->dictLookup("P", &tmp2)->isDict()) { // media play parameters
-    Object params;
-    if (tmp2.dictLookup("MH", &params)->isDict()) {
+  tmp2 = obj->dictLookup("P");
+  if (tmp2.isDict()) { // media play parameters
+    Object params = tmp2.dictLookup("MH");
+    if (params.isDict()) {
       MH.parseMediaPlayParameters(&params);
     }
-    params.free();
-    if (tmp2.dictLookup("BE", &params)->isDict()) {
+    params = tmp2.dictLookup("BE");
+    if (params.isDict()) {
       BE.parseMediaPlayParameters(&params);
     }
-    params.free();
   } else if (!hasClip) {
     error (errSyntaxError, -1, "Invalid Media Rendition");
     ok = gFalse;
   }
-  tmp2.free();
 
   //
   // parse Media Screen Parameters
-  if (obj->dictLookup("SP", &tmp2)->isDict()) { // media screen parameters
-    Object params;
-    if (tmp2.dictLookup("MH", &params)->isDict()) {
+  tmp2 = obj->dictLookup("SP");
+  if (tmp2.isDict()) { // media screen parameters
+    Object params = tmp2.dictLookup("MH");
+    if (params.isDict()) {
       MH.parseMediaScreenParameters(&params);
     }
-    params.free();
-    if (tmp2.dictLookup("BE", &params)->isDict()) {
+    params = tmp2.dictLookup("BE");
+    if (params.isDict()) {
       BE.parseMediaScreenParameters(&params);
     }
-    params.free();
   }
-  tmp2.free();
 }
 
 void MediaRendition::outputToFile(FILE* fp) {
diff --git a/poppler/SecurityHandler.cc b/poppler/SecurityHandler.cc
index 9e0546e3..4eb8d197 100644
--- a/poppler/SecurityHandler.cc
+++ b/poppler/SecurityHandler.cc
@@ -46,13 +46,12 @@
 //------------------------------------------------------------------------
 
 SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) {
-  Object filterObj;
   SecurityHandler *secHdlr;
 #ifdef ENABLE_PLUGINS
   XpdfSecurityHandler *xsh;
 #endif
 
-  encryptDictA->dictLookup("Filter", &filterObj);
+  Object filterObj = encryptDictA->dictLookup("Filter");
   if (filterObj.isName("Standard")) {
     secHdlr = new StandardSecurityHandler(docA, encryptDictA);
   } else if (filterObj.isName()) {
@@ -72,7 +71,6 @@ SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) {
 	  "Missing or invalid 'Filter' entry in encryption dictionary");
     secHdlr = NULL;
   }
-  filterObj.free();
   return secHdlr;
 }
 
@@ -147,13 +145,6 @@ StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA,
 						 Object *encryptDictA):
   SecurityHandler(docA)
 {
-  Object versionObj, revisionObj, lengthObj;
-  Object ownerKeyObj, userKeyObj, ownerEncObj, userEncObj;
-  Object permObj, fileIDObj, fileIDObj1;
-  Object cryptFiltersObj, streamFilterObj, stringFilterObj;
-  Object cryptFilterObj, cfmObj, cfLengthObj;
-  Object encryptMetadataObj;
-
   ok = gFalse;
   fileID = NULL;
   ownerKey = NULL;
@@ -162,21 +153,20 @@ StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA,
   userEnc = NULL;
   fileKeyLength = 0;
 
-  encryptDictA->dictLookup("V", &versionObj);
-  encryptDictA->dictLookup("R", &revisionObj);
-  encryptDictA->dictLookup("Length", &lengthObj);
-  encryptDictA->dictLookup("O", &ownerKeyObj);
-  encryptDictA->dictLookup("U", &userKeyObj);
-  encryptDictA->dictLookup("OE", &ownerEncObj);
-  encryptDictA->dictLookup("UE", &userEncObj);
-  encryptDictA->dictLookup("P", &permObj);
+  Object versionObj = encryptDictA->dictLookup("V");
+  Object revisionObj = encryptDictA->dictLookup("R");
+  Object lengthObj = encryptDictA->dictLookup("Length");
+  Object ownerKeyObj = encryptDictA->dictLookup("O");
+  Object userKeyObj = encryptDictA->dictLookup("U");
+  Object ownerEncObj = encryptDictA->dictLookup("OE");
+  Object userEncObj = encryptDictA->dictLookup("UE");
+  Object permObj = encryptDictA->dictLookup("P");
   if (permObj.isInt64()) {
       unsigned int permUint = permObj.getInt64();
       int perms = permUint - UINT_MAX - 1;
-      permObj.free();
-      permObj.initInt(perms);
+      permObj = Object(perms);
   }
-  doc->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj);
+  Object fileIDObj = doc->getXRef()->getTrailerDict()->dictLookup("ID");
   if (versionObj.isInt() &&
       revisionObj.isInt() &&
       permObj.isInt() &&
@@ -210,9 +200,9 @@ StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA,
       //~ same)
       if ((encVersion == 4 || encVersion == 5) &&
 	  (encRevision == 4 || encRevision == 5 || encRevision == 6)) {
-	encryptDictA->dictLookup("CF", &cryptFiltersObj);
-	encryptDictA->dictLookup("StmF", &streamFilterObj);
-	encryptDictA->dictLookup("StrF", &stringFilterObj);
+	Object cryptFiltersObj = encryptDictA->dictLookup("CF");
+	Object streamFilterObj = encryptDictA->dictLookup("StmF");
+	Object stringFilterObj = encryptDictA->dictLookup("StrF");
 	if (cryptFiltersObj.isDict() &&
 	    streamFilterObj.isName() &&
 	    stringFilterObj.isName() &&
@@ -221,52 +211,43 @@ StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA,
 	    // no encryption on streams or strings
 	    encVersion = encRevision = -1;
 	  } else {
-	    if (cryptFiltersObj.dictLookup(streamFilterObj.getName(),
-					   &cryptFilterObj)->isDict()) {
-	      cryptFilterObj.dictLookup("CFM", &cfmObj);
+	    Object cryptFilterObj = cryptFiltersObj.dictLookup(streamFilterObj.getName());
+	    if (cryptFilterObj.isDict()) {
+	      Object cfmObj = cryptFilterObj.dictLookup("CFM");
 	      if (cfmObj.isName("V2")) {
 		encVersion = 2;
 		encRevision = 3;
-		if (cryptFilterObj.dictLookup("Length",
-					      &cfLengthObj)->isInt()) {
+		Object cfLengthObj = cryptFilterObj.dictLookup("Length");
+		if (cfLengthObj.isInt()) {
 		  //~ according to the spec, this should be cfLengthObj / 8
 		  fileKeyLength = cfLengthObj.getInt();
 		}
-		cfLengthObj.free();
 	      } else if (cfmObj.isName("AESV2")) {
 		encVersion = 2;
 		encRevision = 3;
 		encAlgorithm = cryptAES;
-		if (cryptFilterObj.dictLookup("Length",
-					      &cfLengthObj)->isInt()) {
+		Object cfLengthObj = cryptFilterObj.dictLookup("Length");
+		if (cfLengthObj.isInt()) {
 		  //~ according to the spec, this should be cfLengthObj / 8
 		  fileKeyLength = cfLengthObj.getInt();
 		}
-		cfLengthObj.free();
 	      } else if (cfmObj.isName("AESV3")) {
 		encVersion = 5;
 		// let encRevision be 5 or 6
 		encAlgorithm = cryptAES256;
-		if (cryptFilterObj.dictLookup("Length",
-					      &cfLengthObj)->isInt()) {
+		Object cfLengthObj = cryptFilterObj.dictLookup("Length");
+		if (cfLengthObj.isInt()) {
 		  //~ according to the spec, this should be cfLengthObj / 8
 		  fileKeyLength = cfLengthObj.getInt();
 		}
-		cfLengthObj.free();
 	      }
-	      cfmObj.free();
 	    }
-	    cryptFilterObj.free();
 	  }
 	}
-	stringFilterObj.free();
-	streamFilterObj.free();
-	cryptFiltersObj.free();
-	if (encryptDictA->dictLookup("EncryptMetadata",
-				     &encryptMetadataObj)->isBool()) {
+	Object encryptMetadataObj = encryptDictA->dictLookup("EncryptMetadata");
+	if (encryptMetadataObj.isBool()) {
 	  encryptMetadata = encryptMetadataObj.getBool();
 	}
-	encryptMetadataObj.free();
       }
       permFlags = permObj.getInt();
       ownerKey = ownerKeyObj.getString()->copy();
@@ -274,12 +255,12 @@ StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA,
       if (encVersion >= 1 && encVersion <= 2 &&
 	  encRevision >= 2 && encRevision <= 3) {
 	if (fileIDObj.isArray()) {
-	  if (fileIDObj.arrayGet(0, &fileIDObj1)->isString()) {
+	  Object fileIDObj1 = fileIDObj.arrayGet(0);
+	  if (fileIDObj1.isString()) {
 	    fileID = fileIDObj1.getString()->copy();
 	  } else {
 	    fileID = new GooString();
 	  }
-	  fileIDObj1.free();
 	} else {
 	  fileID = new GooString();
 	}
@@ -310,15 +291,6 @@ StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA,
   } else {
     error(errSyntaxError, -1, "Weird encryption info");
   }
-  fileIDObj.free();
-  permObj.free();
-  userEncObj.free();
-  ownerEncObj.free();
-  userKeyObj.free();
-  ownerKeyObj.free();
-  lengthObj.free();
-  revisionObj.free();
-  versionObj.free();
 }
 
 StandardSecurityHandler::~StandardSecurityHandler() {
@@ -408,7 +380,6 @@ ExternalSecurityHandler::ExternalSecurityHandler(PDFDoc *docA,
 
 ExternalSecurityHandler::~ExternalSecurityHandler() {
   (*xsh->freeDoc)(xsh->handlerData, docData);
-  encryptDict.free();
 }
 
 void *ExternalSecurityHandler::makeAuthData(GooString *ownerPassword,
diff --git a/poppler/Sound.cc b/poppler/Sound.cc
index 6129fdcb..8c82b8f8 100644
--- a/poppler/Sound.cc
+++ b/poppler/Sound.cc
@@ -38,21 +38,18 @@ Sound *Sound::parseSound(Object *obj)
   Dict *dict = str->getDict();
   if (dict == NULL)
     return NULL;
-  Object tmp;
   // the Dict must have the 'R' key of type num
-  dict->lookup("R", &tmp);
+  Object tmp = dict->lookup("R");
   if (tmp.isNum()) {
     return new Sound(obj);
   } else {
-    return NULL;
+    return nullptr;
   }
 }
 
 Sound::Sound(Object *obj, bool readAttrs)
 {
-  streamObj = new Object();
-  streamObj->initNull();
-  obj->copy(streamObj);
+  streamObj = obj->copy();
 
   fileName = NULL;
   samplingRate = 0.0;
@@ -62,43 +59,37 @@ Sound::Sound(Object *obj, bool readAttrs)
 
   if (readAttrs)
   {
-    Object tmp;
-    Dict *dict = streamObj->getStream()->getDict();
-    dict->lookup("F", &tmp);
+    Dict *dict = streamObj.getStream()->getDict();
+    Object tmp = dict->lookup("F");
     if (!tmp.isNull()) {
-      Object obj1;
       // valid 'F' key -> external file
       kind = soundExternal;
-      if (getFileSpecNameForPlatform (&tmp, &obj1)) {
+      Object obj1 = getFileSpecNameForPlatform (&tmp);
+      if (obj1.isString()) {
         fileName = obj1.getString()->copy();
-        obj1.free();
       }
     } else {
       // no file specification, then the sound data have to be
       // extracted from the stream
       kind = soundEmbedded;
     }
-    tmp.free();
     // sampling rate
-    dict->lookup("R", &tmp);
+    tmp = dict->lookup("R");
     if (tmp.isNum()) {
       samplingRate = tmp.getNum();
     }
-    tmp.free();
     // sound channels
-    dict->lookup("C", &tmp);
+    tmp = dict->lookup("C");
     if (tmp.isInt()) {
       channels = tmp.getInt();
     }
-    tmp.free();
     // bits per sample
-    dict->lookup("B", &tmp);
+    tmp = dict->lookup("B");
     if (tmp.isInt()) {
       bitsPerSample = tmp.getInt();
     }
-    tmp.free();
     // encoding format
-    dict->lookup("E", &tmp);
+    tmp = dict->lookup("E");
     if (tmp.isName())
     {
       const char *enc = tmp.getName();
@@ -112,25 +103,22 @@ Sound::Sound(Object *obj, bool readAttrs)
         encoding = soundALaw;
       }
     }
-    tmp.free();
   }
 }
 
 Sound::~Sound()
 {
   delete fileName;
-  streamObj->free();
-  delete streamObj;
 }
 
 Stream *Sound::getStream()
 {
-  return streamObj->getStream();
+  return streamObj.getStream();
 }
 
 Sound *Sound::copy()
 {
-  Sound *newsound = new Sound(streamObj, false);
+  Sound *newsound = new Sound(&streamObj, false);
 
   newsound->kind = kind;
   if (fileName) {
diff --git a/poppler/Sound.h b/poppler/Sound.h
index acb0f8d9..72b89f59 100644
--- a/poppler/Sound.h
+++ b/poppler/Sound.h
@@ -46,7 +46,7 @@ public:
   // Destructor
   ~Sound();
 
-  Object *getObject() { return streamObj; }
+  Object *getObject() { return &streamObj; }
   Stream *getStream();
 
   SoundKind getSoundKind() { return kind; }
@@ -62,7 +62,7 @@ private:
   // Create a sound. The Object obj is ensured to be a Stream with a Dict
   Sound(Object *obj, bool readAttrs = true);
 
-  Object *streamObj;
+  Object streamObj;
   SoundKind kind;
   GooString *fileName;
   double samplingRate;
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index b9fa6cbd..1158ccc2 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -3797,7 +3797,7 @@ void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref,
 				      int maskHeight, GBool maskInvert,
 				      GBool maskInterpolate) {
   GfxImageColorMap *maskColorMap;
-  Object maskDecode, decodeLow, decodeHigh;
+  Object decodeLow, decodeHigh;
   double *ctm;
   SplashCoord mat[6];
   SplashOutMaskedImageData imgData;
@@ -3824,14 +3824,11 @@ void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref,
   // If the mask is higher resolution than the image, use
   // drawSoftMaskedImage() instead.
   if (maskWidth > width || maskHeight > height) {
-    decodeLow.initInt(maskInvert ? 0 : 1);
-    decodeHigh.initInt(maskInvert ? 1 : 0);
-    maskDecode.initArray((xref) ? xref : doc->getXRef());
-    maskDecode.arrayAdd(&decodeLow);
-    maskDecode.arrayAdd(&decodeHigh);
+    Object maskDecode(new Array((xref) ? xref : doc->getXRef()));
+    maskDecode.arrayAdd(Object(maskInvert ? 0 : 1));
+    maskDecode.arrayAdd(Object(maskInvert ? 1 : 0));
     maskColorMap = new GfxImageColorMap(1, &maskDecode,
 					new GfxDeviceGrayColorSpace());
-    maskDecode.free();
     drawSoftMaskedImage(state, ref, str, width, height, colorMap, interpolate,
 			maskStr, maskWidth, maskHeight, maskColorMap, maskInterpolate);
     delete maskColorMap;
@@ -4020,9 +4017,7 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref,
     maskStr->reset();
     maskStr->doGetChars(maskWidth * maskHeight, data);
     maskStr->close();
-    Object maskDict;
-    maskDict.initDict(maskStr->getDict());
-    maskStr = new MemStream((char *)data, 0, maskWidth * maskHeight, &maskDict);
+    maskStr = new MemStream((char *)data, 0, maskWidth * maskHeight, maskStr->getDictObject()->copy());
     ((MemStream *) maskStr)->setNeedFree(gTrue);
   }
   imgMaskData.imgStr = new ImageStream(maskStr, maskWidth,
diff --git a/poppler/StdinPDFDocBuilder.cc b/poppler/StdinPDFDocBuilder.cc
index 571ee46d..29967ec1 100644
--- a/poppler/StdinPDFDocBuilder.cc
+++ b/poppler/StdinPDFDocBuilder.cc
@@ -23,12 +23,9 @@ PDFDoc *
 StdinPDFDocBuilder::buildPDFDoc(const GooString &uri, GooString *ownerPassword,
                                     GooString *userPassword, void *guiDataA)
 {
-  Object obj;
-
-  obj.initNull();
   CachedFile *cachedFile = new CachedFile(new StdinCacheLoader(), NULL);
   return new PDFDoc(new CachedFileStream(cachedFile, 0, gFalse,
-                                         cachedFile->getLength(), &obj),
+                                         cachedFile->getLength(), Object(objNull)),
                     ownerPassword, userPassword);
 }
 
diff --git a/poppler/Stream.cc b/poppler/Stream.cc
index cb91ca5c..7b87912b 100644
--- a/poppler/Stream.cc
+++ b/poppler/Stream.cc
@@ -175,39 +175,33 @@ Stream *Stream::addFilters(Dict *dict, int recursion) {
   int i;
 
   str = this;
-  dict->lookup("Filter", &obj, recursion);
+  obj = dict->lookup("Filter", recursion);
   if (obj.isNull()) {
-    obj.free();
-    dict->lookup("F", &obj, recursion);
+    obj = dict->lookup("F", recursion);
   }
-  dict->lookup("DecodeParms", &params, recursion);
+  params = dict->lookup("DecodeParms", recursion);
   if (params.isNull()) {
-    params.free();
-    dict->lookup("DP", &params, recursion);
+    params = dict->lookup("DP", recursion);
   }
   if (obj.isName()) {
     str = makeFilter(obj.getName(), str, &params, recursion, dict);
   } else if (obj.isArray()) {
     for (i = 0; i < obj.arrayGetLength(); ++i) {
-      obj.arrayGet(i, &obj2, recursion);
+      obj2 = obj.arrayGet(i, recursion);
       if (params.isArray())
-	params.arrayGet(i, &params2, recursion);
+	params2 = params.arrayGet(i, recursion);
       else
-	params2.initNull();
+	params2.setToNull();
       if (obj2.isName()) {
 	str = makeFilter(obj2.getName(), str, &params2, recursion);
       } else {
 	error(errSyntaxError, getPos(), "Bad filter name");
 	str = new EOFStream(str);
       }
-      obj2.free();
-      params2.free();
     }
   } else if (!obj.isNull()) {
     error(errSyntaxError, getPos(), "Bad 'Filter' attribute in stream");
   }
-  obj.free();
-  params.free();
 
   return str;
 }
@@ -234,26 +228,21 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params, int recursio
     bits = 8;
     early = 1;
     if (params->isDict()) {
-      params->dictLookup("Predictor", &obj, recursion);
+      obj = params->dictLookup("Predictor", recursion);
       if (obj.isInt())
 	pred = obj.getInt();
-      obj.free();
-      params->dictLookup("Columns", &obj, recursion);
+      obj = params->dictLookup("Columns", recursion);
       if (obj.isInt())
 	columns = obj.getInt();
-      obj.free();
-      params->dictLookup("Colors", &obj, recursion);
+      obj = params->dictLookup("Colors", recursion);
       if (obj.isInt())
 	colors = obj.getInt();
-      obj.free();
-      params->dictLookup("BitsPerComponent", &obj, recursion);
+      obj = params->dictLookup("BitsPerComponent", recursion);
       if (obj.isInt())
 	bits = obj.getInt();
-      obj.free();
-      params->dictLookup("EarlyChange", &obj, recursion);
+      obj = params->dictLookup("EarlyChange", recursion);
       if (obj.isInt())
 	early = obj.getInt();
-      obj.free();
     }
     str = new LZWStream(str, pred, columns, colors, bits, early);
   } else if (!strcmp(name, "RunLengthDecode") || !strcmp(name, "RL")) {
@@ -267,51 +256,44 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params, int recursio
     endOfBlock = gTrue;
     black = gFalse;
     if (params->isDict()) {
-      params->dictLookup("K", &obj, recursion);
+      obj = params->dictLookup("K", recursion);
       if (obj.isInt()) {
 	encoding = obj.getInt();
       }
-      obj.free();
-      params->dictLookup("EndOfLine", &obj, recursion);
+      obj = params->dictLookup("EndOfLine", recursion);
       if (obj.isBool()) {
 	endOfLine = obj.getBool();
       }
-      obj.free();
-      params->dictLookup("EncodedByteAlign", &obj, recursion);
+      obj = params->dictLookup("EncodedByteAlign", recursion);
       if (obj.isBool()) {
 	byteAlign = obj.getBool();
       }
-      obj.free();
-      params->dictLookup("Columns", &obj, recursion);
+      obj = params->dictLookup("Columns", recursion);
       if (obj.isInt()) {
 	columns = obj.getInt();
       }
-      obj.free();
-      params->dictLookup("Rows", &obj, recursion);
+      obj = params->dictLookup("Rows", recursion);
       if (obj.isInt()) {
 	rows = obj.getInt();
       }
-      obj.free();
-      params->dictLookup("EndOfBlock", &obj, recursion);
+      obj = params->dictLookup("EndOfBlock", recursion);
       if (obj.isBool()) {
 	endOfBlock = obj.getBool();
       }
-      obj.free();
-      params->dictLookup("BlackIs1", &obj, recursion);
+      obj = params->dictLookup("BlackIs1", recursion);
       if (obj.isBool()) {
 	black = obj.getBool();
       }
-      obj.free();
     }
     str = new CCITTFaxStream(str, encoding, endOfLine, byteAlign,
 			     columns, rows, endOfBlock, black);
   } else if (!strcmp(name, "DCTDecode") || !strcmp(name, "DCT")) {
     colorXform = -1;
     if (params->isDict()) {
-      if (params->dictLookup("ColorTransform", &obj, recursion)->isInt()) {
+      obj = params->dictLookup("ColorTransform", recursion);
+      if (obj.isInt()) {
 	colorXform = obj.getInt();
       }
-      obj.free();
     }
     str = new DCTStream(str, colorXform, dict, recursion);
   } else if (!strcmp(name, "FlateDecode") || !strcmp(name, "Fl")) {
@@ -320,33 +302,27 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params, int recursio
     colors = 1;
     bits = 8;
     if (params->isDict()) {
-      params->dictLookup("Predictor", &obj, recursion);
+      obj = params->dictLookup("Predictor", recursion);
       if (obj.isInt())
 	pred = obj.getInt();
-      obj.free();
-      params->dictLookup("Columns", &obj, recursion);
+      obj = params->dictLookup("Columns", recursion);
       if (obj.isInt())
 	columns = obj.getInt();
-      obj.free();
-      params->dictLookup("Colors", &obj, recursion);
+      obj = params->dictLookup("Colors", recursion);
       if (obj.isInt())
 	colors = obj.getInt();
-      obj.free();
-      params->dictLookup("BitsPerComponent", &obj, recursion);
+      obj = params->dictLookup("BitsPerComponent", recursion);
       if (obj.isInt())
 	bits = obj.getInt();
-      obj.free();
     }
     str = new FlateStream(str, pred, columns, colors, bits);
   } else if (!strcmp(name, "JBIG2Decode")) {
     if (params->isDict()) {
       XRef *xref = params->getDict()->getXRef();
-      params->dictLookupNF("JBIG2Globals", &obj);
-      obj.fetch(xref, &globals, recursion);
+      obj = params->dictLookupNF("JBIG2Globals");
+      globals = obj.fetch(xref, recursion);
     }
     str = new JBIG2Stream(str, &globals, &obj);
-    globals.free();
-    obj.free();
   } else if (!strcmp(name, "JPXDecode")) {
     str = new JPXStream(str);
   } else if (!strcmp(name, "Crypt")) {
@@ -416,13 +392,12 @@ void FileOutStream::printf(const char *format, ...)
 // BaseStream
 //------------------------------------------------------------------------
 
-BaseStream::BaseStream(Object *dictA, Goffset lengthA) {
-  dictA->shallowCopy(&dict);
+BaseStream::BaseStream(Object &&dictA, Goffset lengthA) {
+  dict = std::move(dictA);
   length = lengthA;
 }
 
 BaseStream::~BaseStream() {
-  dict.free();
 }
 
 //------------------------------------------------------------------------
@@ -771,8 +746,8 @@ GBool StreamPredictor::getNextLine() {
 //------------------------------------------------------------------------
 
 FileStream::FileStream(GooFile* fileA, Goffset startA, GBool limitedA,
-		       Goffset lengthA, Object *dictA):
-    BaseStream(dictA, lengthA) {
+		       Goffset lengthA, Object &&dictA):
+    BaseStream(std::move(dictA), lengthA) {
   file = fileA;
   offset = start = startA;
   limited = limitedA;
@@ -788,16 +763,12 @@ FileStream::~FileStream() {
 }
 
 BaseStream *FileStream::copy() {
-  Object dictRef;
-  if (dict.isDict()) {
-    dictRef.initDict(dict.getDict());
-  }
-  return new FileStream(file, start, limited, length, &dictRef);
+  return new FileStream(file, start, limited, length, dict.copy());
 }
 
 Stream *FileStream::makeSubStream(Goffset startA, GBool limitedA,
-				  Goffset lengthA, Object *dictA) {
-  return new FileStream(file, startA, limitedA, lengthA, dictA);
+				  Goffset lengthA, Object &&dictA) {
+  return new FileStream(file, startA, limitedA, lengthA, std::move(dictA));
 }
 
 void FileStream::reset() {
@@ -866,8 +837,8 @@ void FileStream::moveStart(Goffset delta) {
 //------------------------------------------------------------------------
 
 CachedFileStream::CachedFileStream(CachedFile *ccA, Goffset startA,
-        GBool limitedA, Goffset lengthA, Object *dictA)
-  : BaseStream(dictA, lengthA)
+        GBool limitedA, Goffset lengthA, Object &&dictA)
+  : BaseStream(std::move(dictA), lengthA)
 {
   cc = ccA;
   start = startA;
@@ -886,20 +857,15 @@ CachedFileStream::~CachedFileStream()
 }
 
 BaseStream *CachedFileStream::copy() {
-  Object dictRef;
-  if (dict.isDict()) {
-    dictRef.initDict(dict.getDict());
-  }
-
   cc->incRefCnt();
-  return new CachedFileStream(cc, start, limited, length, &dictRef);
+  return new CachedFileStream(cc, start, limited, length, dict.copy());
 }
 
 Stream *CachedFileStream::makeSubStream(Goffset startA, GBool limitedA,
-        Goffset lengthA, Object *dictA)
+        Goffset lengthA, Object &&dictA)
 {
   cc->incRefCnt();
-  return new CachedFileStream(cc, startA, limitedA, lengthA, dictA);
+  return new CachedFileStream(cc, startA, limitedA, lengthA, std::move(dictA));
 }
 
 void CachedFileStream::reset()
@@ -974,8 +940,8 @@ void CachedFileStream::moveStart(Goffset delta)
 // MemStream
 //------------------------------------------------------------------------
 
-MemStream::MemStream(char *bufA, Goffset startA, Goffset lengthA, Object *dictA):
-    BaseStream(dictA, lengthA) {
+MemStream::MemStream(char *bufA, Goffset startA, Goffset lengthA, Object &&dictA):
+    BaseStream(std::move(dictA), lengthA) {
   buf = bufA;
   start = startA;
   length = lengthA;
@@ -991,16 +957,11 @@ MemStream::~MemStream() {
 }
 
 BaseStream *MemStream::copy() {
-  Object dictRef;
-  if (dict.isDict()) {
-    dictRef.initDict(dict.getDict());
-  }
-
-  return new MemStream(buf, start, length, &dictRef);
+  return new MemStream(buf, start, length, dict.copy());
 }
 
 Stream *MemStream::makeSubStream(Goffset startA, GBool limited,
-				 Goffset lengthA, Object *dictA) {
+				 Goffset lengthA, Object &&dictA) {
   MemStream *subStr;
   Goffset newLength;
 
@@ -1009,7 +970,7 @@ Stream *MemStream::makeSubStream(Goffset startA, GBool limited,
   } else {
     newLength = lengthA;
   }
-  subStr = new MemStream(buf, startA, newLength, dictA);
+  subStr = new MemStream(buf, startA, newLength, std::move(dictA));
   return subStr;
 }
 
@@ -1062,9 +1023,9 @@ void MemStream::moveStart(Goffset delta) {
 // EmbedStream
 //------------------------------------------------------------------------
 
-EmbedStream::EmbedStream(Stream *strA, Object *dictA,
+EmbedStream::EmbedStream(Stream *strA, Object &&dictA,
 			 GBool limitedA, Goffset lengthA):
-    BaseStream(dictA, lengthA) {
+    BaseStream(std::move(dictA), lengthA) {
   str = strA;
   limited = limitedA;
   length = lengthA;
@@ -1079,7 +1040,7 @@ BaseStream *EmbedStream::copy() {
 }
 
 Stream *EmbedStream::makeSubStream(Goffset start, GBool limitedA,
-				   Goffset lengthA, Object *dictA) {
+				   Goffset lengthA, Object &&dictA) {
   error(errInternal, -1, "Called makeSubStream() on EmbedStream");
   return NULL;
 }
diff --git a/poppler/Stream.h b/poppler/Stream.h
index 740f0fc4..12f23dd6 100644
--- a/poppler/Stream.h
+++ b/poppler/Stream.h
@@ -213,6 +213,7 @@ public:
 
   // Get the dictionary associated with this stream.
   virtual Dict *getDict() = 0;
+  virtual Object *getDictObject() = 0;
 
   // Is this an encoding filter?
   virtual GBool isEncoder() { return gFalse; }
@@ -306,16 +307,18 @@ private:
 class BaseStream: public Stream {
 public:
 
-  BaseStream(Object *dictA, Goffset lengthA);
+    // TODO Mirar si puedo hacer que dictA sea un puntero
+  BaseStream(Object &&dictA, Goffset lengthA);
   ~BaseStream();
   virtual BaseStream *copy() = 0;
   virtual Stream *makeSubStream(Goffset start, GBool limited,
-				Goffset length, Object *dict) = 0;
+				Goffset length, Object &&dict) = 0;
   void setPos(Goffset pos, int dir = 0) override = 0;
   GBool isBinary(GBool last = gTrue) override { return last; }
   BaseStream *getBaseStream() override { return this; }
   Stream *getUndecodedStream() override { return this; }
   Dict *getDict() override { return dict.getDict(); }
+  Object *getDictObject() override { return &dict; }
   virtual GooString *getFileName() { return NULL; }
   virtual Goffset getLength() { return length; }
 
@@ -346,6 +349,7 @@ public:
   BaseStream *getBaseStream() override { return str->getBaseStream(); }
   Stream *getUndecodedStream() override { return str->getUndecodedStream(); }
   Dict *getDict() override { return str->getDict(); }
+  Object *getDictObject() override { return str->getDictObject(); }
   Stream *getNextStream() override { return str; }
 
   int getUnfilteredChar () override { return str->getUnfilteredChar(); }
@@ -447,11 +451,11 @@ class FileStream: public BaseStream {
 public:
 
   FileStream(GooFile* fileA, Goffset startA, GBool limitedA,
-	     Goffset lengthA, Object *dictA);
+	     Goffset lengthA, Object &&dictA);
   ~FileStream();
   BaseStream *copy() override;
   Stream *makeSubStream(Goffset startA, GBool limitedA,
-				Goffset lengthA, Object *dictA) override;
+				Goffset lengthA, Object &&dictA) override;
   StreamKind getKind() override { return strFile; }
   void reset() override;
   void close() override;
@@ -517,11 +521,11 @@ class CachedFileStream: public BaseStream {
 public:
 
   CachedFileStream(CachedFile *ccA, Goffset startA, GBool limitedA,
-	     Goffset lengthA, Object *dictA);
+	     Goffset lengthA, Object &&dictA);
   ~CachedFileStream();
   BaseStream *copy() override;
   Stream *makeSubStream(Goffset startA, GBool limitedA,
-				Goffset lengthA, Object *dictA) override;
+				Goffset lengthA, Object &&dictA) override;
   StreamKind getKind() override { return strCachedFile; }
   void reset() override;
   void close() override;
@@ -560,11 +564,11 @@ private:
 class MemStream: public BaseStream {
 public:
 
-  MemStream(char *bufA, Goffset startA, Goffset lengthA, Object *dictA);
+  MemStream(char *bufA, Goffset startA, Goffset lengthA, Object &&dictA);
   ~MemStream();
   BaseStream *copy() override;
   Stream *makeSubStream(Goffset start, GBool limited,
-				Goffset lengthA, Object *dictA) override;
+				Goffset lengthA, Object &&dictA) override;
   StreamKind getKind() override { return strWeird; }
   void reset() override;
   void close() override;
@@ -609,11 +613,11 @@ private:
 class EmbedStream: public BaseStream {
 public:
 
-  EmbedStream(Stream *strA, Object *dictA, GBool limitedA, Goffset lengthA);
+  EmbedStream(Stream *strA, Object &&dictA, GBool limitedA, Goffset lengthA);
   ~EmbedStream();
   BaseStream *copy() override;
   Stream *makeSubStream(Goffset start, GBool limitedA,
-				Goffset lengthA, Object *dictA) override;
+				Goffset lengthA, Object &&dictA) override;
   StreamKind getKind() override { return str->getKind(); }
   void reset() override {}
   int getChar() override;
diff --git a/poppler/StructElement.cc b/poppler/StructElement.cc
index 0138ad9b..0fbd336a 100644
--- a/poppler/StructElement.cc
+++ b/poppler/StructElement.cc
@@ -170,18 +170,15 @@ static GBool isRGBColor(Object *value)
 
   GBool okay = gTrue;
   for (int i = 0; i < 3; i++) {
-    Object obj;
-    if (!value->arrayGet(i, &obj)->isNum()) {
+    Object obj = value->arrayGet(i);
+    if (!obj.isNum()) {
       okay = gFalse;
-      obj.free();
       break;
     }
     if (obj.getNum() < 0.0 || obj.getNum() > 1.0) {
       okay = gFalse;
-      obj.free();
       break;
     }
-    obj.free();
   }
 
   return okay;
@@ -220,14 +217,11 @@ static GBool isTextString(Object *value)
                                                                         \
       GBool okay = gTrue;                                               \
       for (int i = 0; i < value->arrayGetLength(); i++) {               \
-        Object obj;                                                     \
-        value->arrayGet(i, &obj);                                       \
+        Object obj = value->arrayGet(i);                                \
         if ((!allowNulls && obj.isNull()) || !checkItem(&obj)) {        \
           okay = gFalse;                                                \
-          obj.free();                                                   \
           break;                                                        \
         }                                                               \
-        obj.free();                                                     \
       }                                                                 \
       return okay;                                                      \
     }
@@ -254,46 +248,17 @@ struct AttributeMapEntry {
 };
 
 struct AttributeDefaults {
-  Object Inline;
-  Object LrTb;
-  Object Normal;
-  Object Distribute;
-  Object off;
-  Object Zero;
-  Object Auto;
-  Object Start;
-  Object None;
-  Object Before;
-  Object Nat1;
-
-  AttributeDefaults() {
-    Inline.initName("Inline");
-    LrTb.initName("LrTb");
-    Normal.initName("Normal");
-    Distribute.initName("Distribute");
-    off.initName("off");
-
-    Zero.initReal(0.0);
-    Auto.initName("Auto");
-    Start.initName("Start");
-    None.initName("None");
-    Before.initName("Before");
-    Nat1.initInt(1);
-  }
-
-  ~AttributeDefaults() {
-    Inline.free();
-    LrTb.free();
-    Normal.free();
-    Distribute.free();
-    off.free();
-    Zero.free();
-    Auto.free();
-    Start.free();
-    None.free();
-    Before.free();
-    Nat1.free();
-  }
+  Object Inline  = Object(objName, "Inline");
+  Object LrTb = Object(objName, "LrTb");
+  Object Normal = Object(objName, "Normal");
+  Object Distribute = Object(objName, "Distribute");
+  Object off = Object(objName, "off");
+  Object Zero = Object(0.0);
+  Object Auto = Object(objName, "Auto");
+  Object Start = Object(objName, "Start");
+  Object None = Object(objName, "None");
+  Object Before = Object(objName, "Before");
+  Object Nat1 = Object(1);
 };
 
 static const AttributeDefaults attributeDefaults;
@@ -704,7 +669,7 @@ Attribute::Attribute(const char *nameA, int nameLenA, Object *valueA):
   formatted(NULL)
 {
   assert(valueA);
-  valueA->copy(&value);
+  value = valueA->copy();
 }
 
 Attribute::Attribute(Type type, Object *valueA):
@@ -718,7 +683,7 @@ Attribute::Attribute(Type type, Object *valueA):
 {
   assert(valueA);
 
-  valueA->copy(&value);
+  value = valueA->copy();
 
   if (!checkType())
     type = Unknown;
@@ -727,7 +692,6 @@ Attribute::Attribute(Type type, Object *valueA):
 Attribute::~Attribute()
 {
   delete formatted;
-  value.free();
 }
 
 const char *Attribute::getTypeName() const
@@ -805,10 +769,11 @@ Attribute::Type Attribute::getTypeForName(const char *name, StructElement *eleme
 Attribute *Attribute::parseUserProperty(Dict *property)
 {
   Object obj, value;
-  const char *name = NULL;
+  const char *name = nullptr;
   int nameLen = GooString::CALC_STRING_LEN;
 
-  if (property->lookup("N", &obj)->isString()) {
+  obj = property->lookup("N");
+  if (obj.isString()) {
     GooString *s = obj.getString();
     name = s->getCString();
     nameLen = s->getLength();
@@ -816,34 +781,29 @@ Attribute *Attribute::parseUserProperty(Dict *property)
     name = obj.getName();
   else {
     error(errSyntaxError, -1, "N object is wrong type ({0:s})", obj.getTypeName());
-    obj.free();
-    return NULL;
+    return nullptr;
   }
 
-  if (property->lookup("V", &value)->isNull()) {
+  value = property->lookup("V");
+  if (value.isNull()) {
     error(errSyntaxError, -1, "V object is wrong type ({0:s})", value.getTypeName());
-    value.free();
-    obj.free();
-    return NULL;
+    return nullptr;
   }
 
   Attribute *attribute = new Attribute(name, nameLen, &value);
-  value.free();
-  obj.free();
-
-  if (property->lookup("F", &obj)->isString()) {
+  obj = property->lookup("F");
+  if (obj.isString()) {
     attribute->setFormattedValue(obj.getString()->getCString());
   } else if (!obj.isNull()) {
     error(errSyntaxWarning, -1, "F object is wrong type ({0:s})", obj.getTypeName());
   }
-  obj.free();
 
-  if (property->lookup("H", &obj)->isBool()) {
+  obj = property->lookup("H");
+  if (obj.isBool()) {
     attribute->setHidden(obj.getBool());
   } else if (!obj.isNull()) {
     error(errSyntaxWarning, -1, "H object is wrong type ({0:s})", obj.getTypeName());
   }
-  obj.free();
 
   return attribute;
 }
@@ -871,7 +831,6 @@ StructElement::StructData::~StructData()
   delete id;
   delete title;
   delete language;
-  parentRef.free();
   for (ElemPtrArray::iterator i = elements.begin(); i != elements.end(); ++i) delete *i;
   for (AttrPtrArray::iterator i = attributes.begin(); i != attributes.end(); ++i) delete *i;
 }
@@ -919,7 +878,6 @@ StructElement::~StructElement()
     delete c;
   else
     delete s;
-  pageRef.free();
 }
 
 GBool StructElement::isBlock() const
@@ -1058,21 +1016,22 @@ const TextSpanArray& StructElement::getTextSpansInternal(MarkedContentOutputDev&
   return mcdev.getTextSpans();
 }
 
-static StructElement::Type roleMapResolve(Dict *roleMap, const char *name, const char *curName, Object *resolved)
+static StructElement::Type roleMapResolve(Dict *roleMap, const char *name, const char *curName)
 {
   // Circular reference
   if (curName && !strcmp(name, curName))
     return StructElement::Unknown;
 
-  if (roleMap->lookup(curName ? curName : name, resolved)->isName()) {
-    StructElement::Type type = nameToType(resolved->getName());
+  Object resolved = roleMap->lookup(curName ? curName : name);
+  if (resolved.isName()) {
+    StructElement::Type type = nameToType(resolved.getName());
     return type == StructElement::Unknown
-      ? roleMapResolve(roleMap, name, resolved->getName(), resolved)
+      ? roleMapResolve(roleMap, name, resolved.getName())
       : type;
   }
 
-  if (!resolved->isNull())
-    error(errSyntaxWarning, -1, "RoleMap entry is wrong type ({0:s})", resolved->getTypeName());
+  if (!resolved.isNull())
+    error(errSyntaxWarning, -1, "RoleMap entry is wrong type ({0:s})", resolved.getTypeName());
   return StructElement::Unknown;
 }
 
@@ -1081,31 +1040,30 @@ void StructElement::parse(Dict *element)
   Object obj;
 
   // Type is optional, but if present must be StructElem
-  if (!element->lookup("Type", &obj)->isNull() && !obj.isName("StructElem")) {
+  obj = element->lookup("Type");
+  if (!obj.isNull() && !obj.isName("StructElem")) {
     error(errSyntaxError, -1, "Type of StructElem object is wrong");
-    obj.free();
     return;
   }
-  obj.free();
 
   // Parent object reference (required).
-  if (!element->lookupNF("P", &s->parentRef)->isRef()) {
+  s->parentRef = element->lookupNF("P");
+  if (!s->parentRef.isRef()) {
     error(errSyntaxError, -1, "P object is wrong type ({0:s})", obj.getTypeName());
     return;
   }
 
   // Check whether the S-type is valid for the top level
   // element and create a node of the appropriate type.
-  if (!element->lookup("S", &obj)->isName()) {
+  obj = element->lookup("S");
+  if (!obj.isName()) {
     error(errSyntaxError, -1, "S object is wrong type ({0:s})", obj.getTypeName());
-    obj.free();
     return;
   }
 
   // Type name may not be standard, resolve through RoleMap first.
   if (treeRoot->getRoleMap()) {
-    Object resolvedName;
-    type = roleMapResolve(treeRoot->getRoleMap(), obj.getName(), NULL, &resolvedName);
+    type = roleMapResolve(treeRoot->getRoleMap(), obj.getName(), NULL);
   }
 
   // Resolving through RoleMap may leave type as Unknown, e.g. for types
@@ -1116,67 +1074,66 @@ void StructElement::parse(Dict *element)
   // At this point either the type name must have been resolved.
   if (type == Unknown) {
     error(errSyntaxError, -1, "StructElem object is wrong type ({0:s})", obj.getName());
-    obj.free();
     return;
   }
-  obj.free();
 
   // Object ID (optional), to be looked at the IDTree in the tree root.
-  if (element->lookup("ID", &obj)->isString()) {
+  obj = element->lookup("ID");
+  if (obj.isString()) {
     s->id = obj.takeString();
   }
-  obj.free();
 
   // Page reference (optional) in which at least one of the child items
   // is to be rendered in. Note: each element stores only the /Pg value
   // contained by it, and StructElement::getPageRef() may look in parent
   // elements to find the page where an element belongs.
-  element->lookupNF("Pg", &pageRef);
+  pageRef = element->lookupNF("Pg");
 
   // Revision number (optional).
-  if (element->lookup("R", &obj)->isInt()) {
+  obj = element->lookup("R");
+  if (obj.isInt()) {
     s->revision = obj.getInt();
   }
-  obj.free();
 
   // Element title (optional).
-  if (element->lookup("T", &obj)->isString()) {
+  obj = element->lookup("T");
+  if (obj.isString()) {
     s->title = obj.takeString();
   }
-  obj.free();
 
   // Language (optional).
-  if (element->lookup("Lang", &obj)->isString()) {
+  obj = element->lookup("Lang");
+  if (obj.isString()) {
     s->language = obj.takeString();
   }
-  obj.free();
 
   // Alternative text (optional).
-  if (element->lookup("Alt", &obj)->isString()) {
+  obj = element->lookup("Alt");
+  if (obj.isString()) {
     s->altText = obj.takeString();
   }
-  obj.free();
 
   // Expanded form of an abbreviation (optional).
-  if (element->lookup("E", &obj)->isString()) {
+  obj = element->lookup("E");
+  if (obj.isString()) {
     s->expandedAbbr = obj.takeString();
   }
-  obj.free();
 
   // Actual text (optional).
-  if (element->lookup("ActualText", &obj)->isString()) {
+  obj = element->lookup("ActualText");
+  if (obj.isString()) {
     s->actualText = obj.takeString();
   }
-  obj.free();
 
   // Attributes directly attached to the element (optional).
-  if (element->lookup("A", &obj)->isDict()) {
+  obj = element->lookup("A");
+  if (obj.isDict()) {
     parseAttributes(obj.getDict());
   } else if (obj.isArray()) {
-    Object iobj;
     unsigned attrIndex = getNumAttributes();
     for (int i = 0; i < obj.arrayGetLength(); i++) {
-      if (obj.arrayGet(i, &iobj)->isDict()) {
+      Object iobj = obj.arrayGet(i);
+      if (iobj.isDict()) {
         attrIndex = getNumAttributes();
         parseAttributes(iobj.getDict());
       } else if (iobj.isInt()) {
@@ -1187,25 +1144,23 @@ void StructElement::parse(Dict *element)
       } else {
         error(errSyntaxWarning, -1, "A item is wrong type ({0:s})", iobj.getTypeName());
       }
-      iobj.free();
     }
   } else if (!obj.isNull()) {
     error(errSyntaxWarning, -1, "A is wrong type ({0:s})", obj.getTypeName());
   }
-  obj.free();
 
   // Attributes referenced indirectly through the ClassMap (optional).
   if (treeRoot->getClassMap()) {
-    Object classes;
-    if (element->lookup("C", &classes)->isName()) {
-      Object attr;
-      if (treeRoot->getClassMap()->lookup(classes.getName(), &attr)->isDict()) {
+    Object classes = element->lookup("C");
+    if (classes.isName()) {
+      Object attr = treeRoot->getClassMap()->lookup(classes.getName());
+      if (attr.isDict()) {
         parseAttributes(attr.getDict(), gTrue);
       } else if (attr.isArray()) {
         for (int i = 0; i < attr.arrayGetLength(); i++) {
-          Object iobj;
           unsigned attrIndex = getNumAttributes();
-          if (attr.arrayGet(i, &iobj)->isDict()) {
+          Object iobj = attr.arrayGet(i);
+          if (iobj.isDict()) {
             attrIndex = getNumAttributes();
             parseAttributes(iobj.getDict(), gTrue);
           } else if (iobj.isInt()) {
@@ -1216,13 +1171,10 @@ void StructElement::parse(Dict *element)
           } else {
             error(errSyntaxWarning, -1, "C item is wrong type ({0:s})", iobj.getTypeName());
           }
-          iobj.free();
         }
       } else if (!attr.isNull()) {
         error(errSyntaxWarning, -1, "C object is wrong type ({0:s})", classes.getTypeName());
       }
-      classes.free();
-      attr.free();
     }
   }
 }
@@ -1243,36 +1195,31 @@ StructElement *StructElement::parseChild(Object *ref,
      * TODO: The optional Stm/StwOwn attributes are not handled, so all the
      *      page will be always scanned when calling StructElement::getText().
      */
-    Object mcidObj;
-    Object pageRefObj;
-
-    if (!childObj->dictLookup("MCID", &mcidObj)->isInt()) {
+    Object mcidObj = childObj->dictLookup("MCID");
+    if (mcidObj.isInt()) {
       error(errSyntaxError, -1, "MCID object is wrong type ({0:s})", mcidObj.getTypeName());
-      mcidObj.free();
       return NULL;
     }
 
     child = new StructElement(mcidObj.getInt(), treeRoot, this);
-    mcidObj.free();
 
-    if (childObj->dictLookupNF("Pg", &pageRefObj)->isRef()) {
-      pageRefObj.shallowCopy(&child->pageRef);
+    Object pageRefObj = childObj->dictLookupNF("Pg");
+    if (pageRefObj.isRef()) {
+      child->pageRef = std::move(pageRefObj);
     }
   } else if (childObj->isDict("OBJR")) {
-    Object refObj;
-
-    if (childObj->dictLookupNF("Obj", &refObj)->isRef()) {
-      Object pageRefObj;
+    Object refObj = childObj->dictLookupNF("Obj");
+    if (refObj.isRef()) {
 
       child = new StructElement(refObj.getRef(), treeRoot, this);
 
-      if (childObj->dictLookupNF("Pg", &pageRefObj)->isRef()) {
-        pageRefObj.shallowCopy(&child->pageRef);
+      Object pageRefObj = childObj->dictLookupNF("Pg");
+      if (pageRefObj.isRef()) {
+        child->pageRef = std::move(pageRefObj);
       }
     } else {
       error(errSyntaxError, -1, "Obj object is wrong type ({0:s})", refObj.getTypeName());
     }
-    refObj.free();
   } else if (childObj->isDict()) {
     if (!ref->isRef()) {
       error(errSyntaxError, -1,
@@ -1306,34 +1253,29 @@ StructElement *StructElement::parseChild(Object *ref,
 
 void StructElement::parseChildren(Dict *element, std::set<int> &seen)
 {
-  Object kids;
-
-  if (element->lookup("K", &kids)->isArray()) {
+  Object kids = element->lookup("K");
+  if (kids.isArray()) {
     for (int i = 0; i < kids.arrayGetLength(); i++) {
-      Object obj, ref;
-      parseChild(kids.arrayGetNF(i, &ref), kids.arrayGet(i, &obj), seen);
-      obj.free();
-      ref.free();
+      Object obj = kids.arrayGet(i);
+      Object ref = kids.arrayGetNF(i);
+      parseChild(&ref, &obj, seen);
     }
   } else if (kids.isDict() || kids.isInt()) {
-    Object ref;
-    parseChild(element->lookupNF("K", &ref), &kids, seen);
-    ref.free();
+    Object ref = element->lookupNF("K");
+    parseChild(&ref, &kids, seen);
   }
-
-  kids.free();
 }
 
 void StructElement::parseAttributes(Dict *attributes, GBool keepExisting)
 {
-  Object owner;
-  if (attributes->lookup("O", &owner)->isName("UserProperties")) {
+  Object owner = attributes->lookup("O");
+  if (owner.isName("UserProperties")) {
     // In this case /P is an array of UserProperty dictionaries
-    Object userProperties;
-    if (attributes->lookup("P", &userProperties)->isArray()) {
+    Object userProperties = attributes->lookup("P");
+    if (userProperties.isArray()) {
       for (int i = 0; i < userProperties.arrayGetLength(); i++) {
-        Object property;
-        if (userProperties.arrayGet(i, &property)->isDict()) {
+        Object property = userProperties.arrayGet(i);
+        if (property.isDict()) {
           Attribute *attribute = Attribute::parseUserProperty(property.getDict());
           if (attribute && attribute->isOk()) {
             appendAttribute(attribute);
@@ -1344,10 +1286,8 @@ void StructElement::parseAttributes(Dict *attributes, GBool keepExisting)
         } else {
           error(errSyntaxWarning, -1, "Item in P is wrong type ({0:s})", property.getTypeName());
         }
-        property.free();
       }
     }
-    userProperties.free();
   } else if (owner.isName()) {
     // In this case /P contains standard attributes.
     // Check first if the owner is a valid standard one.
@@ -1374,10 +1314,9 @@ void StructElement::parseAttributes(Dict *attributes, GBool keepExisting)
           }
 
           if (type != Attribute::Unknown) {
-            Object value;
+            Object value = attributes->getVal(i);
             GBool typeCheckOk = gTrue;
-            Attribute *attribute = new Attribute(type, attributes->getVal(i, &value));
-            value.free();
+            Attribute *attribute = new Attribute(type, &value);
 
             if (attribute->isOk() && (typeCheckOk = attribute->checkType(this))) {
               appendAttribute(attribute);
@@ -1401,5 +1340,4 @@ void StructElement::parseAttributes(Dict *attributes, GBool keepExisting)
   } else if (!owner.isNull()) {
     error(errSyntaxWarning, -1, "O is wrong type ({0:s})", owner.getTypeName());
   }
-  owner.free();
 }
diff --git a/poppler/StructTreeRoot.cc b/poppler/StructTreeRoot.cc
index e46e3e28..985096ac 100644
--- a/poppler/StructTreeRoot.cc
+++ b/poppler/StructTreeRoot.cc
@@ -35,8 +35,6 @@ StructTreeRoot::~StructTreeRoot()
 {
   for (ElemPtrArray::iterator i = elements.begin(); i != elements.end(); ++i)
     delete *i;
-  classMap.free();
-  roleMap.free();
 }
 
 void StructTreeRoot::parse(Dict *root)
@@ -44,55 +42,53 @@ void StructTreeRoot::parse(Dict *root)
   // The RoleMap/ClassMap dictionaries are needed by all the parsing
   // functions, which will resolve the custom names to canonical
   // standard names.
-  root->lookup("RoleMap", &roleMap);
-  root->lookup("ClassMap", &classMap);
+  roleMap = root->lookup("RoleMap");
+  classMap = root->lookup("ClassMap");
 
   // ParentTree (optional). If present, it must be a number tree,
   // otherwise it is not possible to map stream objects to their
   // corresponsing structure element. Here only the references are
   // loaded into the array, the pointers to the StructElements will
   // be filled-in later when parsing them.
-  Object obj;
-  if (root->lookup("ParentTree", &obj)->isDict()) {
-    Object nums;
-    if (obj.dictLookup("Nums", &nums)->isArray()) {
+  Object obj = root->lookup("ParentTree");
+  if (obj.isDict()) {
+    Object nums = obj.dictLookup("Nums");
+    if (nums.isArray()) {
       if (nums.arrayGetLength() % 2 == 0) {
         parentTree.resize(nums.arrayGetLength() / 2);
         // Index numbers in even positions, references in odd ones
         for (int i = 0; i < nums.arrayGetLength(); i += 2) {
-          Object index, value;
+          Object index = nums.arrayGet(i);
 
-          if (!nums.arrayGet(i, &index)->isInt()) {
+          if (!index.isInt()) {
             error(errSyntaxError, -1, "Nums item at position {0:d} is wrong type ({1:s})", i, index.getTypeName());
-            index.free();
             continue;
           }
           if (index.getInt() < 0) {
             error(errSyntaxError, -1, "Nums item at position {0:d} is invalid value ({1:d})", i, index.getInt());
-            index.free();
             continue;
           }
 
           const unsigned idx = index.getInt();
-          if (nums.arrayGetNF(i + 1, &value)->isRef()) {
+	  Object value = nums.arrayGetNF(i + 1);
+          if (value.isRef()) {
             parentTree[idx].resize(1);
             parentTree[idx][0].ref = value.getRef();
-          } else if (nums.arrayGet(i + 1, &value)->isArray()) {
-            parentTree[idx].resize(value.arrayGetLength());
-            for (int j = 0; j < value.arrayGetLength(); j++) {
-              Object itemvalue;
-              if (value.arrayGetNF(j, &itemvalue)->isRef())
-                parentTree[idx][j].ref = itemvalue.getRef();
-              else
-                error(errSyntaxError, -1, "Nums array item at position {0:d}/{1:d} is invalid type ({2:s})", i, j, itemvalue.getTypeName());
-              itemvalue.free();
-            }
           } else {
-            error(errSyntaxError, -1, "Nums item at position {0:d} is wrong type ({1:s})", i + 1, value.getTypeName());
-          }
-
-          value.free();
-          index.free();
+	    value = nums.arrayGet(i + 1);
+	    if (value.isArray()) {
+	      parentTree[idx].resize(value.arrayGetLength());
+	      for (int j = 0; j < value.arrayGetLength(); j++) {
+		Object itemvalue = value.arrayGetNF(j);
+		if (itemvalue.isRef())
+		  parentTree[idx][j].ref = itemvalue.getRef();
+		else
+		  error(errSyntaxError, -1, "Nums array item at position {0:d}/{1:d} is invalid type ({2:s})", i, j, itemvalue.getTypeName());
+	      }
+	    } else {
+	      error(errSyntaxError, -1, "Nums item at position {0:d} is wrong type ({1:s})", i + 1, value.getTypeName());
+	    }
+	  }
         }
       } else {
         error(errSyntaxError, -1, "Nums array length is not a even ({0:d})", nums.arrayGetLength());
@@ -100,26 +96,24 @@ void StructTreeRoot::parse(Dict *root)
     } else {
       error(errSyntaxError, -1, "Nums object is wrong type ({0:s})", nums.getTypeName());
     }
-    nums.free();
   }
-  obj.free();
 
   std::set<int> seenElements;
 
   // Parse the children StructElements
   const GBool marked = doc->getCatalog()->getMarkInfo() & Catalog::markInfoMarked;
-  Object kids;
-  if (root->lookup("K", &kids)->isArray()) {
+  Object kids = root->lookup("K");
+  if (kids.isArray()) {
     if (marked && kids.arrayGetLength() > 1) {
       error(errSyntaxWarning, -1, "K in StructTreeRoot has more than one children in a tagged PDF");
     }
     for (int i = 0; i < kids.arrayGetLength(); i++) {
-      Object obj, ref;
-      kids.arrayGetNF(i, &ref);
+      Object ref = kids.arrayGetNF(i);
       if (ref.isRef()) {
         seenElements.insert(ref.getRefNum());
       }
-      if (kids.arrayGet(i, &obj)->isDict()) {
+      Object obj = kids.arrayGet(i);
+      if (obj.isDict()) {
         StructElement *child = new StructElement(obj.getDict(), this, NULL, seenElements);
         if (child->isOk()) {
           if (marked && !(child->getType() == StructElement::Document ||
@@ -139,8 +133,6 @@ void StructTreeRoot::parse(Dict *root)
       } else {
         error(errSyntaxWarning, -1, "K has a child of wrong type ({0:s})", obj.getTypeName());
       }
-      obj.free();
-      ref.free();
     }
   } else if (kids.isDict()) {
     if (marked) {
@@ -149,10 +141,9 @@ void StructTreeRoot::parse(Dict *root)
     StructElement *child = new StructElement(kids.getDict(), this, NULL, seenElements);
     if (child->isOk()) {
       appendChild(child);
-      Object ref;
-      if (root->lookupNF("K", &ref)->isRef())
+      Object ref = root->lookupNF("K");
+      if (ref.isRef())
         parentTreeAdd(ref.getRef(), child);
-      ref.free();
     } else {
       error(errSyntaxWarning, -1, "StructTreeRoot element could not be parsed");
       delete child;
@@ -160,8 +151,6 @@ void StructTreeRoot::parse(Dict *root)
   } else if (!kids.isNull()) {
     error(errSyntaxWarning, -1, "K in StructTreeRoot is wrong type ({0:s})", kids.getTypeName());
   }
-
-  kids.free();
 }
 
 void StructTreeRoot::parentTreeAdd(const Ref &objectRef, StructElement *element)
diff --git a/poppler/ViewerPreferences.cc b/poppler/ViewerPreferences.cc
index cba8d0ac..b81bd271 100644
--- a/poppler/ViewerPreferences.cc
+++ b/poppler/ViewerPreferences.cc
@@ -19,39 +19,38 @@ ViewerPreferences::ViewerPreferences(Dict *prefDict)
 {
   init();
 
-  Object obj;
-
-  if (prefDict->lookup("HideToolbar", &obj)->isBool()) {
+  Object obj = prefDict->lookup("HideToolbar");
+  if (obj.isBool()) {
     hideToolbar = obj.getBool();
   }
-  obj.free();
 
-  if (prefDict->lookup("HideMenubar", &obj)->isBool()) {
+  obj = prefDict->lookup("HideMenubar");
+  if (obj.isBool()) {
     hideMenubar = obj.getBool();
   }
-  obj.free();
 
-  if (prefDict->lookup("HideWindowUI", &obj)->isBool()) {
+  obj = prefDict->lookup("HideWindowUI");
+  if (obj.isBool()) {
     hideWindowUI = obj.getBool();
   }
-  obj.free();
 
-  if (prefDict->lookup("FitWindow", &obj)->isBool()) {
+  obj = prefDict->lookup("FitWindow");
+  if (obj.isBool()) {
     fitWindow = obj.getBool();
   }
-  obj.free();
 
-  if (prefDict->lookup("CenterWindow", &obj)->isBool()) {
+  obj = prefDict->lookup("CenterWindow");
+  if (obj.isBool()) {
     centerWindow = obj.getBool();
   }
-  obj.free();
 
-  if (prefDict->lookup("DisplayDocTitle", &obj)->isBool()) {
+  obj = prefDict->lookup("DisplayDocTitle");
+  if (obj.isBool()) {
     displayDocTitle = obj.getBool();
   }
-  obj.free();
 
-  if (prefDict->lookup("NonFullScreenPageMode", &obj)->isName()) {
+  obj = prefDict->lookup("NonFullScreenPageMode");
+  if (obj.isName()) {
     const char *mode = obj.getName();
     if (!strcmp(mode, "UseNone")) {
       nonFullScreenPageMode = nfpmUseNone;
@@ -63,9 +62,9 @@ ViewerPreferences::ViewerPreferences(Dict *prefDict)
       nonFullScreenPageMode = nfpmUseOC;
     }
   }
-  obj.free();
 
-  if (prefDict->lookup("Direction", &obj)->isName()) {
+  obj = prefDict->lookup("Direction");
+  if (obj.isName()) {
     const char *dir = obj.getName();
     if (!strcmp(dir, "L2R")) {
       direction = directionL2R;
@@ -73,9 +72,9 @@ ViewerPreferences::ViewerPreferences(Dict *prefDict)
       direction = directionR2L;
     }
   }
-  obj.free();
 
-  if (prefDict->lookup("PrintScaling", &obj)->isName()) {
+  obj = prefDict->lookup("PrintScaling");
+  if (obj.isName()) {
     const char *ps = obj.getName();
     if (!strcmp(ps, "None")) {
       printScaling = printScalingNone;
@@ -83,9 +82,9 @@ ViewerPreferences::ViewerPreferences(Dict *prefDict)
       printScaling = printScalingAppDefault;
     }
   }
-  obj.free();
 
-  if (prefDict->lookup("Duplex", &obj)->isName()) {
+  obj = prefDict->lookup("Duplex");
+  if (obj.isName()) {
     const char *d = obj.getName();
     if (!strcmp(d, "Simplex")) {
       duplex = duplexSimplex;
@@ -95,7 +94,6 @@ ViewerPreferences::ViewerPreferences(Dict *prefDict)
       duplex = duplexDuplexFlipLongEdge;
     }
   }
-  obj.free();
 }
 
 ViewerPreferences::~ViewerPreferences()
diff --git a/poppler/XRef.cc b/poppler/XRef.cc
index 854f61fb..2b50f83e 100644
--- a/poppler/XRef.cc
+++ b/poppler/XRef.cc
@@ -99,7 +99,7 @@ public:
 
   // Get the <objIdx>th object from this stream, which should be
   // object number <objNum>, generation 0.
-  Object *getObject(int objIdx, int objNum, Object *obj);
+  Object getObject(int objIdx, int objNum);
 
 private:
 
@@ -145,7 +145,7 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA, int recursion) {
   Stream *str;
   Parser *parser;
   Goffset *offsets;
-  Object objStr, obj1, obj2;
+  Object objStr, obj1;
   Goffset first;
   int i;
 
@@ -155,32 +155,30 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA, int recursion) {
   objNums = NULL;
   ok = gFalse;
 
-  if (!xref->fetch(objStrNum, 0, &objStr, recursion)->isStream()) {
-    goto err1;
+  objStr = xref->fetch(objStrNum, 0, recursion);
+  if (!objStr.isStream()) {
+    return;
   }
 
-  if (!objStr.streamGetDict()->lookup("N", &obj1, recursion)->isInt()) {
-    obj1.free();
-    goto err1;
+  obj1 = objStr.streamGetDict()->lookup("N", recursion);
+  if (!obj1.isInt()) {
+    return;
   }
   nObjects = obj1.getInt();
-  obj1.free();
   if (nObjects <= 0) {
-    goto err1;
+    return;
   }
 
-  objStr.streamGetDict()->lookup("First", &obj1, recursion);
+  obj1 = objStr.streamGetDict()->lookup("First", recursion);
   if (!obj1.isInt() && !obj1.isInt64()) {
-    obj1.free();
-    goto err1;
+    return;
   }
   if (obj1.isInt())
     first = obj1.getInt();
   else
     first = obj1.getInt64();
-  obj1.free();
   if (first < 0) {
-    goto err1;
+    return;
   }
 
   // this is an arbitrary limit to avoid integer overflow problems
@@ -188,7 +186,7 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA, int recursion) {
   // object streams to 100-200 objects)
   if (nObjects > 1000000) {
     error(errSyntaxError, -1, "Too many objects in an object stream");
-    goto err1;
+    return;
   }
   objs = new Object[nObjects];
   objNums = (int *)gmallocn(nObjects, sizeof(int));
@@ -196,31 +194,26 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA, int recursion) {
 
   // parse the header: object numbers and offsets
   objStr.streamReset();
-  obj1.initNull();
-  str = new EmbedStream(objStr.getStream(), &obj1, gTrue, first);
+  str = new EmbedStream(objStr.getStream(), Object(objNull), gTrue, first);
   parser = new Parser(xref, new Lexer(xref, str), gFalse);
   for (i = 0; i < nObjects; ++i) {
-    parser->getObj(&obj1);
-    parser->getObj(&obj2);
+    obj1 = parser->getObj();
+    Object obj2 = parser->getObj();
     if (!obj1.isInt() || !(obj2.isInt() || obj2.isInt64())) {
-      obj1.free();
-      obj2.free();
       delete parser;
       gfree(offsets);
-      goto err1;
+      return;
     }
     objNums[i] = obj1.getInt();
     if (obj2.isInt())
       offsets[i] = obj2.getInt();
     else
       offsets[i] = obj2.getInt64();
-    obj1.free();
-    obj2.free();
     if (objNums[i] < 0 || offsets[i] < 0 ||
 	(i > 0 && offsets[i] < offsets[i-1])) {
       delete parser;
       gfree(offsets);
-      goto err1;
+      return;
     }
   }
   while (str->getChar() != EOF) ;
@@ -235,43 +228,32 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA, int recursion) {
 
   // parse the objects
   for (i = 0; i < nObjects; ++i) {
-    obj1.initNull();
     if (i == nObjects - 1) {
-      str = new EmbedStream(objStr.getStream(), &obj1, gFalse, 0);
+      str = new EmbedStream(objStr.getStream(), Object(objNull), gFalse, 0);
     } else {
-      str = new EmbedStream(objStr.getStream(), &obj1, gTrue,
+      str = new EmbedStream(objStr.getStream(), Object(objNull), gTrue,
 			    offsets[i+1] - offsets[i]);
     }
     parser = new Parser(xref, new Lexer(xref, str), gFalse);
-    parser->getObj(&objs[i]);
+    objs[i] = parser->getObj();
     while (str->getChar() != EOF) ;
     delete parser;
   }
 
   gfree(offsets);
   ok = gTrue;
-
- err1:
-  objStr.free();
 }
 
 ObjectStream::~ObjectStream() {
-  int i;
-
-  if (objs) {
-    for (i = 0; i < nObjects; ++i) {
-      objs[i].free();
-    }
-    delete[] objs;
-  }
+  delete[] objs;
   gfree(objNums);
 }
 
-Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) {
+Object ObjectStream::getObject(int objIdx, int objNum) {
   if (objIdx < 0 || objIdx >= nObjects || objNum != objNums[objIdx]) {
-    return obj->initNull();
+    return Object(objNull);
   }
-  return objs[objIdx].copy(obj);
+  return objs[objIdx].copy();
 }
 
 //------------------------------------------------------------------------
@@ -311,7 +293,7 @@ XRef::XRef(Object *trailerDictA) {
   init();
 
   if (trailerDictA->isDict())
-    trailerDict.initDict(trailerDictA->getDict());
+    trailerDict = trailerDictA->copy();
 }
 
 XRef::XRef(BaseStream *strA, Goffset pos, Goffset mainXRefEntriesOffsetA, GBool *wasReconstructed, GBool reconstruct) {
@@ -356,30 +338,26 @@ XRef::XRef(BaseStream *strA, Goffset pos, Goffset mainXRefEntriesOffsetA, GBool
     }
 
     // set size to (at least) the size specified in trailer dict
-    trailerDict.dictLookupNF("Size", &obj);
+    obj = trailerDict.dictLookupNF("Size");
     if (!obj.isInt()) {
         error(errSyntaxWarning, -1, "No valid XRef size in trailer");
     } else {
       if (obj.getInt() > size) {
          if (resize(obj.getInt()) != obj.getInt()) {
             if (!(ok = constructXRef(wasReconstructed))) {
-               obj.free();
                errCode = errDamaged;
                return;
             }
          }
       }
     }
-    obj.free();
 
     // get the root dictionary (catalog) object
-    trailerDict.dictLookupNF("Root", &obj);
+    obj = trailerDict.dictLookupNF("Root");
     if (obj.isRef()) {
       rootNum = obj.getRefNum();
       rootGen = obj.getRefGen();
-      obj.free();
     } else {
-      obj.free();
       if (!(ok = constructXRef(wasReconstructed))) {
         errCode = errDamaged;
         return;
@@ -397,7 +375,6 @@ XRef::~XRef() {
   }
   gfree(entries);
 
-  trailerDict.free();
   if (streamEnds) {
     gfree(streamEnds);
   }
@@ -426,7 +403,7 @@ XRef *XRef::copy() {
   xref->prevXRefOffset = prevXRefOffset;
   xref->mainXRefEntriesOffset = mainXRefEntriesOffset;
   xref->xRefStream = xRefStream;
-  trailerDict.copy(&xref->trailerDict);
+  xref->trailerDict = trailerDict.copy();
   xref->encAlgorithm = encAlgorithm;
   xref->encRevision = encRevision;
   xref->encVersion = encVersion;
@@ -446,7 +423,7 @@ XRef *XRef::copy() {
   for (int i = 0; i < size; ++i) {
     xref->entries[i].offset = entries[i].offset;
     xref->entries[i].type = entries[i].type;
-    xref->entries[i].obj.initNull ();
+    xref->entries[i].obj.setToNull();
     xref->entries[i].flags = entries[i].flags;
     xref->entries[i].gen = entries[i].gen;
   }
@@ -495,7 +472,7 @@ int XRef::resize(int newSize)
     for (int i = size; i < newSize; ++i) {
       entries[i].offset = -1;
       entries[i].type = xrefEntryNone;
-      entries[i].obj.initNullNoFree ();
+      entries[i].obj.initNullAfterMalloc ();
       entries[i].flags = 0;
       entries[i].gen = 0;
     }
@@ -529,31 +506,26 @@ GBool XRef::readXRef(Goffset *pos, std::vector<Goffset> *followedXRefStm, std::v
   GBool more;
 
   // start up a parser, parse one token
-  obj.initNull();
   parser = new Parser(NULL,
 	     new Lexer(NULL,
-	       str->makeSubStream(start + *pos, gFalse, 0, &obj)),
+	       str->makeSubStream(start + *pos, gFalse, 0, Object(objNull))),
 	     gTrue);
-  parser->getObj(&obj, gTrue);
+  obj = parser->getObj(gTrue);
 
   // parse an old-style xref table
   if (obj.isCmd("xref")) {
-    obj.free();
     more = readXRefTable(parser, pos, followedXRefStm, xrefStreamObjsNum);
 
   // parse an xref stream
   } else if (obj.isInt()) {
     const int objNum = obj.getInt();
-    obj.free();
-    if (!parser->getObj(&obj, gTrue)->isInt()) {
+    if (obj = parser->getObj(gTrue), !obj.isInt()) {
       goto err1;
     }
-    obj.free();
-    if (!parser->getObj(&obj, gTrue)->isCmd("obj")) {
+    if (obj = parser->getObj(gTrue), !obj.isCmd("obj")) {
       goto err1;
     }
-    obj.free();
-    if (!parser->getObj(&obj)->isStream()) {
+    if (obj = parser->getObj(), !obj.isStream()) {
       goto err1;
     }
     if (trailerDict.isNone()) {
@@ -563,7 +535,6 @@ GBool XRef::readXRef(Goffset *pos, std::vector<Goffset> *followedXRefStm, std::v
       xrefStreamObjsNum->push_back(objNum);
     }
     more = readXRefStream(obj.getStream(), pos);
-    obj.free();
 
   } else {
     goto err1;
@@ -573,7 +544,6 @@ GBool XRef::readXRef(Goffset *pos, std::vector<Goffset> *followedXRefStm, std::v
   return more;
 
  err1:
-  obj.free();
   delete parser;
   ok = gFalse;
   return gFalse;
@@ -587,21 +557,19 @@ GBool XRef::readXRefTable(Parser *parser, Goffset *pos, std::vector<Goffset> *fo
   int first, n, i;
 
   while (1) {
-    parser->getObj(&obj, gTrue);
+    obj = parser->getObj(gTrue);
     if (obj.isCmd("trailer")) {
-      obj.free();
       break;
     }
     if (!obj.isInt()) {
-      goto err1;
+      goto err0;
     }
     first = obj.getInt();
-    obj.free();
-    if (!parser->getObj(&obj, gTrue)->isInt()) {
-      goto err1;
+    obj = parser->getObj(gTrue);
+    if (!obj.isInt()) {
+      goto err0;
     }
     n = obj.getInt();
-    obj.free();
     if (first < 0 || n < 0 || first + n < 0) {
       goto err0;
     }
@@ -612,36 +580,34 @@ GBool XRef::readXRefTable(Parser *parser, Goffset *pos, std::vector<Goffset> *fo
       }
     }
     for (i = first; i < first + n; ++i) {
-      parser->getObj(&obj, gTrue);
+      obj = parser->getObj(gTrue);
       if (obj.isInt()) {
 	entry.offset = obj.getInt();
       } else if (obj.isInt64()) {
 	entry.offset = obj.getInt64();
       } else {
-	goto err1;
+	goto err0;
       }
-      obj.free();
-      if (!parser->getObj(&obj, gTrue)->isInt()) {
-	goto err1;
+      obj = parser->getObj(gTrue);
+      if (!obj.isInt()) {
+	goto err0;
       }
       entry.gen = obj.getInt();
       entry.flags = 0;
-      obj.free();
-      parser->getObj(&obj, gTrue);
+      obj = parser->getObj(gTrue);
       if (obj.isCmd("n")) {
 	entry.type = xrefEntryUncompressed;
       } else if (obj.isCmd("f")) {
 	entry.type = xrefEntryFree;
       } else {
-	goto err1;
+	goto err0;
       }
-      obj.free();
       if (entries[i].offset == -1) {
 	entries[i].offset = entry.offset;
 	entries[i].gen = entry.gen;
 	entries[i].type = entry.type;
 	entries[i].flags = entry.flags;
-	entries[i].obj.initNull();
+	entries[i].obj.setToNull();
 
 	// PDF files of patents from the IBM Intellectual Property
 	// Network have a bug: the xref table claims to start at 1
@@ -654,7 +620,7 @@ GBool XRef::readXRefTable(Parser *parser, Goffset *pos, std::vector<Goffset> *fo
 	  entries[0].gen = 65535;
 	  entries[0].type = xrefEntryFree;
 	  entries[0].flags = entries[1].flags;
-	  entries[1].obj.shallowCopy(&entries[0].obj);
+	  entries[0].obj = std::move(entries[1].obj);
 
 	  entries[1].offset = -1;
 	}
@@ -663,12 +629,13 @@ GBool XRef::readXRefTable(Parser *parser, Goffset *pos, std::vector<Goffset> *fo
   }
 
   // read the trailer dictionary
-  if (!parser->getObj(&obj)->isDict()) {
-    goto err1;
+  obj = parser->getObj();
+  if (!obj.isDict()) {
+    goto err0;
   }
 
   // get the 'Prev' pointer
-  obj.getDict()->lookupNF("Prev", &obj2);
+  obj2 = obj.getDict()->lookupNF("Prev");
   if (obj2.isInt() || obj2.isInt64()) {
     if (obj2.isInt())
       pos2 = obj2.getInt();
@@ -695,15 +662,14 @@ GBool XRef::readXRefTable(Parser *parser, Goffset *pos, std::vector<Goffset> *fo
   } else {
     more = gFalse;
   }
-  obj2.free();
 
   // save the first trailer dictionary
   if (trailerDict.isNone()) {
-    obj.copy(&trailerDict);
+    trailerDict = obj.copy();
   }
 
   // check for an 'XRefStm' key
-  obj.getDict()->lookup("XRefStm", &obj2);
+  obj2 = obj.getDict()->lookup("XRefStm");
   if (obj2.isInt() || obj2.isInt64()) {
     if (obj2.isInt())
       pos2 = obj2.getInt();
@@ -719,97 +685,84 @@ GBool XRef::readXRefTable(Parser *parser, Goffset *pos, std::vector<Goffset> *fo
       readXRef(&pos2, followedXRefStm, xrefStreamObjsNum);
     }
     if (!ok) {
-      obj2.free();
-      goto err1;
+      goto err0;
     }
   }
-  obj2.free();
 
-  obj.free();
   return more;
 
- err1:
-  obj.free();
  err0:
   ok = gFalse;
   return gFalse;
 }
 
 GBool XRef::readXRefStream(Stream *xrefStr, Goffset *pos) {
-  Dict *dict;
   int w[3];
   GBool more;
-  Object obj, obj2, idx;
-  int newSize, first, n, i;
+  Object obj;
 
-  dict = xrefStr->getDict();
+  ok = gFalse;
 
-  if (!dict->lookupNF("Size", &obj)->isInt()) {
-    goto err1;
+  Dict *dict = xrefStr->getDict();
+  obj = dict->lookupNF("Size");
+  if (!obj.isInt()) {
+    return gFalse;
   }
-  newSize = obj.getInt();
-  obj.free();
+  int newSize = obj.getInt();
   if (newSize < 0) {
-    goto err1;
+    return gFalse;
   }
   if (newSize > size) {
     if (resize(newSize) != newSize) {
       error(errSyntaxError, -1, "Invalid 'size' parameter");
-      goto err0;
+      return gFalse;
     }
   }
 
-  if (!dict->lookupNF("W", &obj)->isArray() ||
-      obj.arrayGetLength() < 3) {
-    goto err1;
+  obj = dict->lookupNF("W");
+  if (!obj.isArray() || obj.arrayGetLength() < 3) {
+    return gFalse;
   }
-  for (i = 0; i < 3; ++i) {
-    if (!obj.arrayGet(i, &obj2)->isInt()) {
-      obj2.free();
-      goto err1;
+  for (int i = 0; i < 3; ++i) {
+    Object obj2 = obj.arrayGet(i);
+    if (!obj2.isInt()) {
+      return gFalse;
     }
     w[i] = obj2.getInt();
-    obj2.free();
     if (w[i] < 0) {
-      goto err1;
+      return gFalse;
     }
   }
-  obj.free();
   if (w[0] > (int)sizeof(int) || w[1] > (int)sizeof(long long) || w[2] > (int)sizeof(int)) {
-    goto err1;
+    return gFalse;
   }
 
   xrefStr->reset();
-  dict->lookupNF("Index", &idx);
+  Object idx = dict->lookupNF("Index");
   if (idx.isArray()) {
-    for (i = 0; i+1 < idx.arrayGetLength(); i += 2) {
-      if (!idx.arrayGet(i, &obj)->isInt()) {
-	idx.free();
-	goto err1;
+    for (int i = 0; i+1 < idx.arrayGetLength(); i += 2) {
+      obj = idx.arrayGet(i);
+      if (!obj.isInt()) {
+	return gFalse;
       }
-      first = obj.getInt();
-      obj.free();
-      if (!idx.arrayGet(i+1, &obj)->isInt()) {
-	idx.free();
-	goto err1;
+      int first = obj.getInt();
+      obj = idx.arrayGet(i+1);
+      if (!obj.isInt()) {
+	return gFalse;
       }
-      n = obj.getInt();
-      obj.free();
+      int n = obj.getInt();
       if (first < 0 || n < 0 ||
 	  !readXRefStreamSection(xrefStr, w, first, n)) {
-	idx.free();
-	goto err0;
+	return gFalse;
       }
     }
   } else {
     if (!readXRefStreamSection(xrefStr, w, 0, newSize)) {
-      idx.free();
-      goto err0;
+      return gFalse;
     }
   }
-  idx.free();
 
-  dict->lookupNF("Prev", &obj);
+  obj = dict->lookupNF("Prev");
   if (obj.isInt()) {
     *pos = obj.getInt();
     more = gTrue;
@@ -819,18 +772,12 @@ GBool XRef::readXRefStream(Stream *xrefStr, Goffset *pos) {
   } else {
     more = gFalse;
   }
-  obj.free();
   if (trailerDict.isNone()) {
-    trailerDict.initDict(dict);
+    trailerDict = xrefStr->getDictObject()->copy();
   }
 
+  ok = gTrue;
   return more;
-
- err1:
-  obj.free();
- err0:
-  ok = gFalse;
-  return gFalse;
 }
 
 GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) {
@@ -906,7 +853,7 @@ GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) {
 // Attempt to construct an xref table for a damaged file.
 GBool XRef::constructXRef(GBool *wasReconstructed, GBool needCatalogDict) {
   Parser *parser;
-  Object newTrailerDict, obj;
+  Object obj;
   char buf[256];
   Goffset pos;
   int num, gen;
@@ -956,26 +903,20 @@ GBool XRef::constructXRef(GBool *wasReconstructed, GBool needCatalogDict) {
 
       // got trailer dictionary
       if (!strncmp(p, "trailer", 7)) {
-        obj.initNull();
         parser = new Parser(NULL,
 		 new Lexer(NULL,
-		   str->makeSubStream(pos + 7, gFalse, 0, &obj)),
+		   str->makeSubStream(pos + 7, gFalse, 0, Object(objNull))),
 		 gFalse);
-        parser->getObj(&newTrailerDict);
+        Object newTrailerDict = parser->getObj();
         if (newTrailerDict.isDict()) {
-	  newTrailerDict.dictLookupNF("Root", &obj);
+	  obj = newTrailerDict.dictLookupNF("Root");
 	  if (obj.isRef() && (!gotRoot || !needCatalogDict) && rootNum != obj.getRefNum()) {
 	    rootNum = obj.getRefNum();
 	    rootGen = obj.getRefGen();
-	    if (!trailerDict.isNone()) {
-	      trailerDict.free();
-	    }
-	    newTrailerDict.copy(&trailerDict);
+	    trailerDict = newTrailerDict.copy();
 	    gotRoot = gTrue;
 	  }
-	  obj.free();
         }
-        newTrailerDict.free();
         delete parser;
 
       // look for object
@@ -1152,20 +1093,19 @@ GBool XRef::okToAssemble(GBool ignoreOwnerPW) {
   return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permAssemble);
 }
 
-Object *XRef::getCatalog(Object *catalog) {
-  fetch(rootNum, rootGen, catalog);
-  if (catalog->isDict()) {
+Object XRef::getCatalog() {
+  Object catalog = fetch(rootNum, rootGen);
+  if (catalog.isDict()) {
     return catalog;
   }
   GBool wasReconstructed = false;
   if (constructXRef(&wasReconstructed, gTrue)) {
-    catalog->free();
-    fetch(rootNum, rootGen, catalog);
+    catalog = fetch(rootNum, rootGen);
   }
   return catalog;
 }
 
-Object *XRef::fetch(int num, int gen, Object *obj, int recursion) {
+Object XRef::fetch(int num, int gen, int recursion) {
   XRefEntry *e;
   Parser *parser;
   Object obj1, obj2, obj3;
@@ -1178,24 +1118,23 @@ Object *XRef::fetch(int num, int gen, Object *obj, int recursion) {
 
   e = getEntry(num);
   if(!e->obj.isNull ()) { //check for updated object
-    obj = e->obj.copy(obj);
-    return obj;
+    return e->obj.copy();
   }
 
   switch (e->type) {
 
   case xrefEntryUncompressed:
+  {
     if (e->gen != gen) {
       goto err;
     }
-    obj1.initNull();
     parser = new Parser(this,
 	       new Lexer(this,
-		 str->makeSubStream(start + e->offset, gFalse, 0, &obj1)),
+		 str->makeSubStream(start + e->offset, gFalse, 0, Object(objNull))),
 	       gTrue);
-    parser->getObj(&obj1, recursion);
-    parser->getObj(&obj2, recursion);
-    parser->getObj(&obj3, recursion);
+    obj1 = parser->getObj(recursion);
+    obj2 = parser->getObj(recursion);
+    obj3 = parser->getObj(recursion);
     if (!obj1.isInt() || obj1.getInt() != num ||
 	!obj2.isInt() || obj2.getInt() != gen ||
 	!obj3.isCmd("obj")) {
@@ -1214,28 +1153,19 @@ Object *XRef::fetch(int num, int gen, Object *obj, int recursion) {
 	  if (longNumber <= INT_MAX && longNumber >= INT_MIN && *end_ptr == '\0') {
 	    int number = longNumber;
 	    error(errSyntaxWarning, -1, "Cmd was not obj but {0:s}, assuming the creator meant obj {1:d}", cmd, number);
-	    obj->initInt(number);
-	    obj1.free();
-	    obj2.free();
-	    obj3.free();
 	    delete parser;
-	    break;
+	    return Object(number);
 	  }
 	}
       }
-      obj1.free();
-      obj2.free();
-      obj3.free();
       delete parser;
       goto err;
     }
-    parser->getObj(obj, gFalse, (encrypted && !e->getFlag(XRefEntry::Unencrypted)) ? fileKey : NULL,
+    Object obj = parser->getObj(gFalse, (encrypted && !e->getFlag(XRefEntry::Unencrypted)) ? fileKey : NULL,
 		   encAlgorithm, keyLength, num, gen, recursion);
-    obj1.free();
-    obj2.free();
-    obj3.free();
     delete parser;
-    break;
+    return obj;
+  }
 
   case xrefEntryCompressed:
   {
@@ -1272,24 +1202,21 @@ Object *XRef::fetch(int num, int gen, Object *obj, int recursion) {
 	objStrs->put(newkey, newitem);
       }
     }
-    objStr->getObject(e->gen, num, obj);
+    return objStr->getObject(e->gen, num);
   }
-  break;
 
   default:
     goto err;
   }
   
-  return obj;
-
  err:
   if (!xRefStream && !xrefReconstructed) {
     error(errInternal, -1, "xref num {0:d} not found but needed, try to reconstruct\n", num);
     rootNum = -1;
     constructXRef(&xrefReconstructed);
-    return fetch(num, gen, obj, ++recursion);
+    return fetch(num, gen, ++recursion);
   }
-  return obj->initNull();
+  return Object(objNull);
 }
 
 void XRef::lock() {
@@ -1304,43 +1231,34 @@ void XRef::unlock() {
 #endif
 }
 
-Object *XRef::getDocInfo(Object *obj) {
-  return trailerDict.dictLookup("Info", obj);
+Object XRef::getDocInfo() {
+  return trailerDict.dictLookup("Info");
 }
 
 // Added for the pdftex project.
-Object *XRef::getDocInfoNF(Object *obj) {
-  return trailerDict.dictLookupNF("Info", obj);
+Object XRef::getDocInfoNF() {
+  return trailerDict.dictLookupNF("Info");
 }
 
-Object *XRef::createDocInfoIfNoneExists(Object *obj) {
-  getDocInfo(obj);
+Object XRef::createDocInfoIfNoneExists() {
+  Object obj = getDocInfo();
 
-  if (obj->isDict()) {
+  if (obj.isDict()) {
     return obj;
-  } else if (!obj->isNull()) {
+  } else if (!obj.isNull()) {
     // DocInfo exists, but isn't a dictionary (doesn't comply with the PDF reference)
-    obj->free();
     removeDocInfo();
   }
 
-  obj->initDict(this);
-
-  Ref ref = addIndirectObject(obj);
-
-  Object objRef;
-  objRef.initRef(ref.num, ref.gen);
-
-  trailerDict.dictSet("Info", &objRef);
-
-  objRef.free();
+  obj = Object(new Dict(this));
+  const Ref ref = addIndirectObject(&obj);
+  trailerDict.dictSet("Info", Object(ref.num, ref.gen));
 
   return obj;
 }
 
 void XRef::removeDocInfo() {
-  Object infoObjRef;
-  getDocInfoNF(&infoObjRef);
+  Object infoObjRef = getDocInfoNF();
   if (infoObjRef.isNull()) {
     return;
   }
@@ -1348,7 +1266,6 @@ void XRef::removeDocInfo() {
   trailerDict.dictRemove("Info");
 
   removeIndirectObject(infoObjRef.getRef());
-  infoObjRef.free();
 }
 
 GBool XRef::getStreamEnd(Goffset streamStart, Goffset *streamEnd) {
@@ -1405,7 +1322,7 @@ void XRef::add(int num, int gen, Goffset offs, GBool used) {
     for (int i = size; i < num + 1; ++i) {
       entries[i].offset = -1;
       entries[i].type = xrefEntryFree;
-      entries[i].obj.initNull ();
+      entries[i].obj.setToNull();
       entries[i].flags = 0;
       entries[i].gen = 0;
     }
@@ -1413,7 +1330,7 @@ void XRef::add(int num, int gen, Goffset offs, GBool used) {
   }
   XRefEntry *e = getEntry(num);
   e->gen = gen;
-  e->obj.initNull ();
+  e->obj.setToNull();
   e->flags = 0;
   if (used) {
     e->type = xrefEntryUncompressed;
@@ -1431,8 +1348,7 @@ void XRef::setModifiedObject (Object* o, Ref r) {
     return;
   }
   XRefEntry *e = getEntry(r.num);
-  e->obj.free();
-  o->copy(&(e->obj));
+  e->obj = o->copy();
   e->setFlag(XRefEntry::Updated, gTrue);
   setModified();
 }
@@ -1458,7 +1374,7 @@ Ref XRef::addIndirectObject (Object* o) {
     //incremented when the object was deleted
   }
   e->type = xrefEntryUncompressed;
-  o->copy(&e->obj);
+  e->obj = o->copy();
   e->setFlag(XRefEntry::Updated, gTrue);
   setModified();
 
@@ -1547,16 +1463,15 @@ void XRef::writeTableToFile(OutStream* outStr, GBool writeAllEntries) {
   writeXRef(&writer, writeAllEntries);
 }
 
-XRef::XRefStreamWriter::XRefStreamWriter(Object *indexA, GooString *stmBufA, int offsetSizeA) {
+XRef::XRefStreamWriter::XRefStreamWriter(Array *indexA, GooString *stmBufA, int offsetSizeA) {
   index = indexA;
   stmBuf = stmBufA;
   offsetSize = offsetSizeA;
 }
 
 void XRef::XRefStreamWriter::startSection(int first, int count) {
-  Object obj;
-  index->arrayAdd( obj.initInt(first) );
-  index->arrayAdd( obj.initInt(count) );
+  index->add( Object(first) );
+  index->add( Object(count) );
 }
 
 void XRef::XRefStreamWriter::writeEntry(Goffset offset, int gen, XRefEntryType type) {
@@ -1585,8 +1500,7 @@ void XRef::XRefPreScanWriter::writeEntry(Goffset offset, int gen, XRefEntryType
 }
 
 void XRef::writeStreamToBuffer(GooString *stmBuf, Dict *xrefDict, XRef *xref) {
-  Object index;
-  index.initArray(xref);
+  Array *index = new Array(xref);
   stmBuf->clear();
 
   // First pass: determine whether all offsets fit in 4 bytes or not
@@ -1595,47 +1509,41 @@ void XRef::writeStreamToBuffer(GooString *stmBuf, Dict *xrefDict, XRef *xref) {
   const int offsetSize = prescan.hasOffsetsBeyond4GB ? sizeof(Goffset) : 4;
 
   // Second pass: actually write the xref stream
-  XRefStreamWriter writer(&index, stmBuf, offsetSize);
+  XRefStreamWriter writer(index, stmBuf, offsetSize);
   writeXRef(&writer, gFalse);
 
-  Object obj1, obj2;
-  xrefDict->set("Type", obj1.initName("XRef"));
-  xrefDict->set("Index", &index);
-  obj2.initArray(xref);
-  obj2.arrayAdd( obj1.initInt(1) );
-  obj2.arrayAdd( obj1.initInt(offsetSize) );
-  obj2.arrayAdd( obj1.initInt(2) );
-  xrefDict->set("W", &obj2);
+  xrefDict->set("Type", Object(objName, "XRef"));
+  xrefDict->set("Index", Object(index));
+  Array *wArray = new Array(xref);
+  wArray->add( Object(1) );
+  wArray->add( Object(offsetSize) );
+  wArray->add( Object(2) );
+  xrefDict->set("W", Object(wArray));
 }
 
 GBool XRef::parseEntry(Goffset offset, XRefEntry *entry)
 {
   GBool r;
 
-  Object obj;
-  obj.initNull();
   Parser parser(NULL, new Lexer(NULL,
-     str->makeSubStream(offset, gFalse, 20, &obj)), gTrue);
+     str->makeSubStream(offset, gFalse, 20, Object(objNull))), gTrue);
 
   Object obj1, obj2, obj3;
-  if (((parser.getObj(&obj1)->isInt()) || obj1.isInt64()) &&
-      (parser.getObj(&obj2)->isInt()) &&
-      (parser.getObj(&obj3)->isCmd("n") || obj3.isCmd("f"))) {
+  if (((obj1 = parser.getObj(), obj1.isInt()) || obj1.isInt64()) &&
+      (obj2 = parser.getObj(), obj2.isInt()) &&
+      (obj3 = parser.getObj(), obj3.isCmd("n") || obj3.isCmd("f"))) {
     if (obj1.isInt64())
       entry->offset = obj1.getInt64();
     else
       entry->offset = obj1.getInt();
     entry->gen = obj2.getInt();
     entry->type = obj3.isCmd("n") ? xrefEntryUncompressed : xrefEntryFree;
-    entry->obj.initNull ();
+    entry->obj.setToNull();
     entry->flags = 0;
     r = gTrue;
   } else {
     r = gFalse;
   }
-  obj1.free();
-  obj2.free();
-  obj3.free();
 
   return r;
 }
@@ -1728,8 +1636,8 @@ void XRef::markUnencrypted(Object *obj) {
     {
       Array *array = obj->getArray();
       for (int i = 0; i < array->getLength(); i++) {
-        markUnencrypted(array->getNF(i, &obj1));
-        obj1.free();
+	obj1 = array->getNF(i);
+        markUnencrypted(&obj1);
       }
       break;
     }
@@ -1744,8 +1652,8 @@ void XRef::markUnencrypted(Object *obj) {
         dict = obj->getDict();
       }
       for (int i = 0; i < dict->getLength(); i++) {
-        markUnencrypted(dict->getValNF(i, &obj1));
-        obj1.free();
+	obj1 = dict->getValNF(i);
+        markUnencrypted(&obj1);
       }
       break;
     }
@@ -1756,9 +1664,8 @@ void XRef::markUnencrypted(Object *obj) {
       if (e->getFlag(XRefEntry::Unencrypted))
         return; // We've already been here: prevent infinite recursion
       e->setFlag(XRefEntry::Unencrypted, gTrue);
-      fetch(ref.num, ref.gen, &obj1);
+      obj1 = fetch(ref.num, ref.gen);
       markUnencrypted(&obj1);
-      obj1.free();
       break;
     }
     default:
@@ -1802,19 +1709,16 @@ void XRef::scanSpecialFlags() {
   }
 
   // Mark objects referred from the Encrypt dict as Unencrypted
-  Object obj;
-  markUnencrypted(trailerDict.dictLookupNF("Encrypt", &obj));
-  obj.free();
+  Object obj = trailerDict.dictLookupNF("Encrypt");
+  markUnencrypted();
 }
 
 void XRef::markUnencrypted() {
   // Mark objects referred from the Encrypt dict as Unencrypted
-  Object obj;
-  trailerDict.dictLookupNF("Encrypt", &obj);
+  Object obj = trailerDict.dictLookupNF("Encrypt");
   if (obj.isRef()) {
     XRefEntry *e = getEntry(obj.getRefNum());
     e->setFlag(XRefEntry::Unencrypted, gTrue);
   }
-  obj.free();
 }
 
diff --git a/poppler/XRef.h b/poppler/XRef.h
index 0439161d..3915b587 100644
--- a/poppler/XRef.h
+++ b/poppler/XRef.h
@@ -141,18 +141,18 @@ public:
   int getPermFlags() { return permFlags; }
 
   // Get catalog object.
-  Object *getCatalog(Object *obj);
+  Object getCatalog();
 
   // Fetch an indirect reference.
-  Object *fetch(int num, int gen, Object *obj, int recursion = 0);
+  Object fetch(int num, int gen, int recursion = 0);
 
   // Return the document's Info dictionary (if any).
-  Object *getDocInfo(Object *obj);
-  Object *getDocInfoNF(Object *obj);
+  Object getDocInfo();
+  Object getDocInfoNF();
 
   // Create and return the document's Info dictionary if none exists.
   // Otherwise return the existing one.
-  Object *createDocInfoIfNoneExists(Object *obj);
+  Object createDocInfoIfNoneExists();
 
   // Remove the document's Info dictionary and update the trailer dictionary.
   void removeDocInfo();
@@ -271,11 +271,11 @@ private:
   // XRefWriter subclass that writes a XRef stream
   class XRefStreamWriter: public XRefWriter {
   public:
-    XRefStreamWriter(Object *index, GooString *stmBuf, int offsetSize);
+    XRefStreamWriter(Array *index, GooString *stmBuf, int offsetSize);
     void startSection(int first, int count) override;
     void writeEntry(Goffset offset, int gen, XRefEntryType type) override;
   private:
-    Object *index;
+    Array *index;
     GooString *stmBuf;
     int offsetSize;
   };
diff --git a/qt4/src/poppler-annotation-helper.h b/qt4/src/poppler-annotation-helper.h
index 5f335c04..e1362504 100644
--- a/qt4/src/poppler-annotation-helper.h
+++ b/qt4/src/poppler-annotation-helper.h
@@ -50,83 +50,71 @@ class XPDFReader
 
 void XPDFReader::lookupName( Dict * dict, char * type, QString & dest )
 {
-    Object nameObj;
-    dict->lookup( type, &nameObj );
+    Object nameObj = dict->lookup( type );
     if ( nameObj.isNull() )
         return;
     if ( nameObj.isName() )
         dest = nameObj.getName();
     else
         qDebug() << type << " is not Name." << endl;
-    nameObj.free();
 }
 
 void XPDFReader::lookupString( Dict * dict, char * type, QString & dest )
 {
-    Object stringObj;
-    dict->lookup( type, &stringObj );
+    Object stringObj = dict->lookup( type );
     if ( stringObj.isNull() )
         return;
     if ( stringObj.isString() )
         dest = stringObj.getString()->getCString();
     else
         qDebug() << type << " is not String." << endl;
-    stringObj.free();
 }
 
 void XPDFReader::lookupBool( Dict * dict, char * type, bool & dest )
 {
-    Object boolObj;
-    dict->lookup( type, &boolObj );
+    Object boolObj = dict->lookup( type );
     if ( boolObj.isNull() )
         return;
     if ( boolObj.isBool() )
         dest = boolObj.getBool() == gTrue;
     else
         qDebug() << type << " is not Bool." << endl;
-    boolObj.free();
 }
 
 void XPDFReader::lookupInt( Dict * dict, char * type, int & dest )
 {
-    Object intObj;
-    dict->lookup( type, &intObj );
+    Object intObj = dict->lookup( type );
     if ( intObj.isNull() )
         return;
     if ( intObj.isInt() )
         dest = intObj.getInt();
     else
         qDebug() << type << " is not Int." << endl;
-    intObj.free();
 }
 
 void XPDFReader::lookupNum( Dict * dict, char * type, double & dest )
 {
-    Object numObj;
-    dict->lookup( type, &numObj );
+    Object numObj = dict->lookup( type );
     if ( numObj.isNull() )
         return;
     if ( numObj.isNum() )
         dest = numObj.getNum();
     else
         qDebug() << type << " is not Num." << endl;
-    numObj.free();
 }
 
 int XPDFReader::lookupNumArray( Dict * dict, char * type, double * dest, int len )
 {
-    Object arrObj;
-    dict->lookup( type, &arrObj );
+    Object arrObj = dict->lookup( type );
     if ( arrObj.isNull() )
         return 0;
-    Object numObj;
     if ( arrObj.isArray() )
     {
         len = qMin( len, arrObj.arrayGetLength() );
         for ( int i = 0; i < len; i++ )
         {
-            dest[i] = arrObj.arrayGet( i, &numObj )->getNum();
-            numObj.free();
+            Object numObj = arrObj.arrayGet( i );
+            dest[i] = numObj.getNum();
         }
     }
     else
@@ -134,7 +122,6 @@ int XPDFReader::lookupNumArray( Dict * dict, char * type, double * dest, int len
         len = 0;
         qDebug() << type << "is not Array." << endl;
     }
-    arrObj.free();
     return len;
 }
 
@@ -147,21 +134,18 @@ void XPDFReader::lookupColor( Dict * dict, char * type, QColor & dest )
 
 void XPDFReader::lookupIntRef( Dict * dict, char * type, int & dest )
 {
-    Object refObj;
-    dict->lookupNF( type, &refObj );
+    Object refObj = dict->lookupNF( type );
     if ( refObj.isNull() )
         return;
     if ( refObj.isRef() )
         dest = refObj.getRefNum();
     else
         qDebug() << type << " is not Ref." << endl;
-    refObj.free();
 }
 
 void XPDFReader::lookupDate( Dict * dict, char * type, QDateTime & dest )
 {
-    Object dateObj;
-    dict->lookup( type, &dateObj );
+    Object dateObj = dict->lookup( type );
     if ( dateObj.isNull() )
         return;
     if ( dateObj.isString() )
@@ -170,7 +154,6 @@ void XPDFReader::lookupDate( Dict * dict, char * type, QDateTime & dest )
     }
     else
         qDebug() << type << " is not Date" << endl;
-    dateObj.free();
 }
 
 void XPDFReader::transform( double * M, double x, double y, QPointF &res )
diff --git a/qt4/src/poppler-document.cc b/qt4/src/poppler-document.cc
index 7f8abfa7..3c5a6f99 100644
--- a/qt4/src/poppler-document.cc
+++ b/qt4/src/poppler-document.cc
@@ -257,12 +257,10 @@ namespace Poppler {
 	QByteArray result;
 	if (fi.isEmbedded())
 	{
-		Object refObj, strObj;
 		XRef *xref = m_doc->doc->getXRef()->copy();
 
-		refObj.initRef(fi.m_data->embRef.num, fi.m_data->embRef.gen);
-		refObj.fetch(xref, &strObj);
-		refObj.free();
+		Object refObj(fi.m_data->embRef.num, fi.m_data->embRef.gen);
+		Object strObj = refObj.fetch(xref);
 		if (strObj.isStream())
 		{
 			int c;
@@ -273,7 +271,6 @@ namespace Poppler {
 			}
 			strObj.streamClose();
 		}
-		strObj.free();
 		delete xref;
 	}
 	return result;
@@ -434,14 +431,13 @@ namespace Poppler {
     {
 	QStringList keys;
 
-	Object info;
 	if ( m_doc->locked )
 	    return QStringList();
 
 	QScopedPointer<XRef> xref(m_doc->doc->getXRef()->copy());
 	if (!xref)
 		return QStringList();
-	xref->getDocInfo(&info);
+	Object info = xref->getDocInfo();
 	if ( !info.isDict() )
 	    return QStringList();
 
@@ -452,7 +448,6 @@ namespace Poppler {
 	    keys.append( QString::fromAscii(infoDict->getKey(i)) );
 	}
 
-	info.free();
 	return keys;
     }
 
diff --git a/qt4/src/poppler-form.cc b/qt4/src/poppler-form.cc
index 12aa3295..98b6ee6b 100644
--- a/qt4/src/poppler-form.cc
+++ b/qt4/src/poppler-form.cc
@@ -191,8 +191,8 @@ QString FormFieldButton::caption() const
   if (fwb->getButtonType() == formButtonPush)
   {
     Dict *dict = m_formData->fm->getObj()->getDict();
-    Object obj1;
-    if (dict->lookup("MK", &obj1)->isDict())
+    Object obj1 = dict->lookup("MK");
+    if (obj1.isDict())
     {
       AnnotAppearanceCharacs appearCharacs(obj1.getDict());
       if (appearCharacs.getNormalCaption())
@@ -200,7 +200,6 @@ QString FormFieldButton::caption() const
         ret = UnicodeParsedString(appearCharacs.getNormalCaption());
       }
     }
-    obj1.free();
   }
   else
   {
diff --git a/qt4/src/poppler-optcontent.cc b/qt4/src/poppler-optcontent.cc
index a5b651aa..715c8a43 100644
--- a/qt4/src/poppler-optcontent.cc
+++ b/qt4/src/poppler-optcontent.cc
@@ -41,8 +41,7 @@ namespace Poppler
   {
     itemsInGroup.reserve( rbarray->getLength() );
     for (int i = 0; i < rbarray->getLength(); ++i) {
-      Object ref;
-      rbarray->getNF( i, &ref );
+      Object ref = rbarray->getNF( i );
       if ( ! ref.isRef() ) {
 	qDebug() << "expected ref, but got:" << ref.getType();
       }
@@ -199,11 +198,9 @@ namespace Poppler
   {
     OptContentItem *lastItem = parentNode;
     for (int i = 0; i < orderArray->getLength(); ++i) {
-      Object orderItem;
-      orderArray->get(i, &orderItem);
+      Object orderItem = orderArray->get(i);
       if ( orderItem.isDict() ) {
-	Object item;
-	orderArray->getNF(i, &item);
+	Object item = orderArray->getNF(i);
 	if (item.isRef() ) {
           OptContentItem *ocItem = m_optContentItems.value(QString::number(item.getRefNum()), 0);
 	  if (ocItem) {
@@ -213,7 +210,6 @@ namespace Poppler
             qDebug() << "could not find group for object" << item.getRefNum();
 	  }
 	}
-	item.free();
       } else if ( (orderItem.isArray()) && (orderItem.arrayGetLength() > 0) ) {
 	parseOrderArray(lastItem, orderItem.getArray());
       } else if ( orderItem.isString() ) {
@@ -226,7 +222,6 @@ namespace Poppler
       } else {
 	qDebug() << "something unexpected";
       }	
-      orderItem.free();
     }
   }
 
@@ -237,8 +232,7 @@ namespace Poppler
     }
     // This is an array of array(s)
     for (int i = 0; i < rBGroupArray->getLength(); ++i) {
-      Object rbObj;
-      rBGroupArray->get(i, &rbObj);
+      Object rbObj = rBGroupArray->get(i);
       if ( ! rbObj.isArray() ) {
 	qDebug() << "expected inner array, got:" << rbObj.getType();
 	return;
@@ -246,7 +240,6 @@ namespace Poppler
       Array *rbarray = rbObj.getArray();
       RadioButtonGroup *rbg = new RadioButtonGroup( this, rbarray );
       m_rbgroups.append( rbg );
-      rbObj.free();
     }
   }
 
diff --git a/qt4/src/poppler-page.cc b/qt4/src/poppler-page.cc
index fb6a036d..95d21290 100644
--- a/qt4/src/poppler-page.cc
+++ b/qt4/src/poppler-page.cc
@@ -650,11 +650,10 @@ QList<TextBox*> Page::textList(Rotation rotate) const
 PageTransition *Page::transition() const
 {
   if (!m_page->transition) {
-    Object o;
     PageTransitionParams params;
-    params.dictObj = m_page->page->getTrans(&o);
-    if (params.dictObj->isDict()) m_page->transition = new PageTransition(params);
-    o.free();
+    Object o = m_page->page->getTrans();
+    params.dictObj = &o;
+    if (o.isDict()) m_page->transition = new PageTransition(params);
   }
   return m_page->transition;
 }
@@ -663,20 +662,15 @@ Link *Page::action( PageAction act ) const
 {
   if ( act == Page::Opening || act == Page::Closing )
   {
-    Object o;
-    m_page->page->getActions(&o);
+    Object o = m_page->page->getActions();
     if (!o.isDict())
     {
-      o.free();
       return 0;
     }
     Dict *dict = o.getDict();
-    Object o2;
     const char *key = act == Page::Opening ? "O" : "C";
-    dict->lookup((char*)key, &o2);
+    Object o2 = dict->lookup((char*)key);
     ::LinkAction *lact = ::LinkAction::parseAction(&o2, m_page->parentDoc->doc->getCatalog()->getBaseURI() );
-    o2.free();
-    o.free();
     Link *popplerLink = NULL;
     if (lact != NULL)
     {
diff --git a/qt4/src/poppler-private.h b/qt4/src/poppler-private.h
index 0c0731c2..7af40146 100644
--- a/qt4/src/poppler-private.h
+++ b/qt4/src/poppler-private.h
@@ -103,10 +103,8 @@ namespace Poppler {
 	
 	DocumentData(const QByteArray &data, GooString *ownerPassword, GooString *userPassword)
 	    {
-		Object obj;
 		fileContents = data;
-		obj.initNull();
-		MemStream *str = new MemStream((char*)fileContents.data(), 0, fileContents.length(), &obj);
+		MemStream *str = new MemStream((char*)fileContents.data(), 0, fileContents.length(), Object(objNull));
 		init();
 		doc = new PDFDoc(str, ownerPassword, userPassword);
 		delete ownerPassword;
diff --git a/qt4/tests/check_lexer.cpp b/qt4/tests/check_lexer.cpp
index 243a5927..93c3621d 100644
--- a/qt4/tests/check_lexer.cpp
+++ b/qt4/tests/check_lexer.cpp
@@ -13,112 +13,91 @@ private slots:
 void TestLexer::testNumbers()
 {
     char data[] = "0 1 -1 2147483647 -2147483647 2147483648 -2147483648 4294967297 -2147483649 0.1 1.1 -1.1 2147483647.1 -2147483647.1 2147483648.1 -2147483648.1 4294967297.1 -2147483649.1 9223372036854775807 18446744073709551615";
-    Object dummy;
-    MemStream *stream = new MemStream(data, 0, strlen(data), &dummy);
+    MemStream *stream = new MemStream(data, 0, strlen(data), Object(objNull));
     Lexer *lexer = new Lexer(NULL, stream);
     QVERIFY( lexer );
     
     Object obj;
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), 0);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), 1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), -1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), 2147483647);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), -2147483647);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt64);
     QCOMPARE(obj.getInt64(), 2147483648ll);
-    obj.free();
       
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), -2147483647-1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt64);
     QCOMPARE(obj.getInt64(), 4294967297ll);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt64);
     QCOMPARE(obj.getInt64(), -2147483649ll);
-    obj.free();
 
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 0.1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 1.1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), -1.1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 2147483647.1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), -2147483647.1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 2147483648.1);
-    obj.free();
       
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), -2147483648.1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 4294967297.1);
-    obj.free();
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), -2147483649.1);
-    obj.free();
 
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt64);
     QCOMPARE(obj.getInt64(), 9223372036854775807ll);
-    obj.free();
 
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 18446744073709551616.);
-    obj.free();
 
     delete lexer;
 }
diff --git a/qt4/tests/check_optcontent.cpp b/qt4/tests/check_optcontent.cpp
index 22b14a45..2de29952 100644
--- a/qt4/tests/check_optcontent.cpp
+++ b/qt4/tests/check_optcontent.cpp
@@ -101,66 +101,57 @@ void TestOptionalContent::checkIsVisible()
 
     // AnyOn, one element array:
     // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QVERIFY( ocgs->optContentIsVisible( &obj ) );
-    obj.free();
 
     // Same again, looking for any leaks or dubious free()'s
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QVERIFY( ocgs->optContentIsVisible( &obj ) );
-    obj.free();
 
     // AnyOff, one element array:
     // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
-    xref->fetch( 29, 0, &obj );
+    obj = xref->fetch( 29, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOn, one element array:
     // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
-    xref->fetch( 36, 0, &obj );
+    obj = xref->fetch( 36, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
 
     // AllOff, one element array:
     // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
-    xref->fetch( 43, 0, &obj );
+    obj = xref->fetch( 43, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOn, multi-element array:
     // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
-    xref->fetch( 50, 0, &obj );
+    obj = xref->fetch( 50, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOff, multi-element array:
     // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 57, 0, &obj );
+    obj = xref->fetch( 57, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOn, multi-element array:
     // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 64, 0, &obj );
+    obj = xref->fetch( 64, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOff, multi-element array:
     // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 71, 0, &obj );
+    obj = xref->fetch( 71, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     delete doc;
     delete globalParams;
@@ -182,8 +173,7 @@ void TestOptionalContent::checkVisibilitySetting()
 
     // In this test, both Ref(21,0) and Ref(28,0) start On,
     // based on the file settings
-    Object ref21obj;
-    ref21obj.initRef( 21, 0 );
+    Object ref21obj( 21, 0 );
     Ref ref21 = ref21obj.getRef();
     OptionalContentGroup *ocgA = ocgs->findOcgByRef( ref21 );
     QVERIFY( ocgA );
@@ -191,8 +181,7 @@ void TestOptionalContent::checkVisibilitySetting()
     QVERIFY( (ocgA->getName()->cmp("A")) == 0 );
     QCOMPARE( ocgA->getState(), OptionalContentGroup::On );
 
-    Object ref28obj;
-    ref28obj.initRef( 28, 0 );
+    Object ref28obj( 28, 0 );
     Ref ref28 = ref28obj.getRef();
     OptionalContentGroup *ocgB = ocgs->findOcgByRef( ref28 );
     QVERIFY( ocgB );
@@ -205,65 +194,56 @@ void TestOptionalContent::checkVisibilitySetting()
 
     // AnyOn, one element array:
     // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // Same again, looking for any leaks or dubious free()'s
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOff, one element array:
     // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
-    xref->fetch( 29, 0, &obj );
+    obj = xref->fetch( 29, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, one element array:
     // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
-    xref->fetch( 36, 0, &obj );
+    obj = xref->fetch( 36, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOff, one element array:
     // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
-    xref->fetch( 43, 0, &obj );
+    obj = xref->fetch( 43, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOn, multi-element array:
     // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
-    xref->fetch( 50, 0, &obj );
+    obj = xref->fetch( 50, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOff, multi-element array:
     // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 57, 0, &obj );
+    obj = xref->fetch( 57, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, multi-element array:
     // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 64, 0, &obj );
+    obj = xref->fetch( 64, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, multi-element array:
     // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 71, 0, &obj );
+    obj = xref->fetch( 71, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
 
     // Turn the other one off as well (i.e. both are Off)
@@ -271,65 +251,56 @@ void TestOptionalContent::checkVisibilitySetting()
 
     // AnyOn, one element array:
     // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // Same again, looking for any leaks or dubious free()'s
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOff, one element array:
     // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
-    xref->fetch( 29, 0, &obj );
+    obj = xref->fetch( 29, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, one element array:
     // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
-    xref->fetch( 36, 0, &obj );
+    obj = xref->fetch( 36, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, one element array:
     // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
-    xref->fetch( 43, 0, &obj );
+    obj = xref->fetch( 43, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOn, multi-element array:
     // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
-    xref->fetch( 50, 0, &obj );
+    obj = xref->fetch( 50, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOff, multi-element array:
     // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 57, 0, &obj );
+    obj = xref->fetch( 57, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, multi-element array:
     // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 64, 0, &obj );
+    obj = xref->fetch( 64, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, multi-element array:
     // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 71, 0, &obj );
+    obj = xref->fetch( 71, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
 
     // Turn the first one on again (21 is On, 28 is Off)
@@ -337,65 +308,56 @@ void TestOptionalContent::checkVisibilitySetting()
 
     // AnyOn, one element array:
     // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // Same again, looking for any leaks or dubious free()'s
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOff, one element array:
     // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
-    xref->fetch( 29, 0, &obj );
+    obj = xref->fetch( 29, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOn, one element array:
     // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
-    xref->fetch( 36, 0, &obj );
+    obj = xref->fetch( 36, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, one element array:
     // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
-    xref->fetch( 43, 0, &obj );
+    obj = xref->fetch( 43, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOn, multi-element array:
     // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
-    xref->fetch( 50, 0, &obj );
+    obj = xref->fetch( 50, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOff, multi-element array:
     // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 57, 0, &obj );
+    obj = xref->fetch( 57, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, multi-element array:
     // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 64, 0, &obj );
+    obj = xref->fetch( 64, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, multi-element array:
     // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 71, 0, &obj );
+    obj = xref->fetch( 71, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     delete doc;
     delete globalParams;
diff --git a/qt5/src/poppler-annotation-helper.h b/qt5/src/poppler-annotation-helper.h
index 5f335c04..e1362504 100644
--- a/qt5/src/poppler-annotation-helper.h
+++ b/qt5/src/poppler-annotation-helper.h
@@ -50,83 +50,71 @@ class XPDFReader
 
 void XPDFReader::lookupName( Dict * dict, char * type, QString & dest )
 {
-    Object nameObj;
-    dict->lookup( type, &nameObj );
+    Object nameObj = dict->lookup( type );
     if ( nameObj.isNull() )
         return;
     if ( nameObj.isName() )
         dest = nameObj.getName();
     else
         qDebug() << type << " is not Name." << endl;
-    nameObj.free();
 }
 
 void XPDFReader::lookupString( Dict * dict, char * type, QString & dest )
 {
-    Object stringObj;
-    dict->lookup( type, &stringObj );
+    Object stringObj = dict->lookup( type );
     if ( stringObj.isNull() )
         return;
     if ( stringObj.isString() )
         dest = stringObj.getString()->getCString();
     else
         qDebug() << type << " is not String." << endl;
-    stringObj.free();
 }
 
 void XPDFReader::lookupBool( Dict * dict, char * type, bool & dest )
 {
-    Object boolObj;
-    dict->lookup( type, &boolObj );
+    Object boolObj = dict->lookup( type );
     if ( boolObj.isNull() )
         return;
     if ( boolObj.isBool() )
         dest = boolObj.getBool() == gTrue;
     else
         qDebug() << type << " is not Bool." << endl;
-    boolObj.free();
 }
 
 void XPDFReader::lookupInt( Dict * dict, char * type, int & dest )
 {
-    Object intObj;
-    dict->lookup( type, &intObj );
+    Object intObj = dict->lookup( type );
     if ( intObj.isNull() )
         return;
     if ( intObj.isInt() )
         dest = intObj.getInt();
     else
         qDebug() << type << " is not Int." << endl;
-    intObj.free();
 }
 
 void XPDFReader::lookupNum( Dict * dict, char * type, double & dest )
 {
-    Object numObj;
-    dict->lookup( type, &numObj );
+    Object numObj = dict->lookup( type );
     if ( numObj.isNull() )
         return;
     if ( numObj.isNum() )
         dest = numObj.getNum();
     else
         qDebug() << type << " is not Num." << endl;
-    numObj.free();
 }
 
 int XPDFReader::lookupNumArray( Dict * dict, char * type, double * dest, int len )
 {
-    Object arrObj;
-    dict->lookup( type, &arrObj );
+    Object arrObj = dict->lookup( type );
     if ( arrObj.isNull() )
         return 0;
-    Object numObj;
     if ( arrObj.isArray() )
     {
         len = qMin( len, arrObj.arrayGetLength() );
         for ( int i = 0; i < len; i++ )
         {
-            dest[i] = arrObj.arrayGet( i, &numObj )->getNum();
-            numObj.free();
+            Object numObj = arrObj.arrayGet( i );
+            dest[i] = numObj.getNum();
         }
     }
     else
@@ -134,7 +122,6 @@ int XPDFReader::lookupNumArray( Dict * dict, char * type, double * dest, int len
         len = 0;
         qDebug() << type << "is not Array." << endl;
     }
-    arrObj.free();
     return len;
 }
 
@@ -147,21 +134,18 @@ void XPDFReader::lookupColor( Dict * dict, char * type, QColor & dest )
 
 void XPDFReader::lookupIntRef( Dict * dict, char * type, int & dest )
 {
-    Object refObj;
-    dict->lookupNF( type, &refObj );
+    Object refObj = dict->lookupNF( type );
     if ( refObj.isNull() )
         return;
     if ( refObj.isRef() )
         dest = refObj.getRefNum();
     else
         qDebug() << type << " is not Ref." << endl;
-    refObj.free();
 }
 
 void XPDFReader::lookupDate( Dict * dict, char * type, QDateTime & dest )
 {
-    Object dateObj;
-    dict->lookup( type, &dateObj );
+    Object dateObj = dict->lookup( type );
     if ( dateObj.isNull() )
         return;
     if ( dateObj.isString() )
@@ -170,7 +154,6 @@ void XPDFReader::lookupDate( Dict * dict, char * type, QDateTime & dest )
     }
     else
         qDebug() << type << " is not Date" << endl;
-    dateObj.free();
 }
 
 void XPDFReader::transform( double * M, double x, double y, QPointF &res )
diff --git a/qt5/src/poppler-document.cc b/qt5/src/poppler-document.cc
index 741a1b7f..b3261872 100644
--- a/qt5/src/poppler-document.cc
+++ b/qt5/src/poppler-document.cc
@@ -243,12 +243,10 @@ namespace Poppler {
 	QByteArray result;
 	if (fi.isEmbedded())
 	{
-		Object refObj, strObj;
 		XRef *xref = m_doc->doc->getXRef()->copy();
 
-		refObj.initRef(fi.m_data->embRef.num, fi.m_data->embRef.gen);
-		refObj.fetch(xref, &strObj);
-		refObj.free();
+		Object refObj(fi.m_data->embRef.num, fi.m_data->embRef.gen);
+		Object strObj = refObj.fetch(xref);
 		if (strObj.isStream())
 		{
 			int c;
@@ -259,7 +257,6 @@ namespace Poppler {
 			}
 			strObj.streamClose();
 		}
-		strObj.free();
 		delete xref;
 	}
 	return result;
@@ -420,14 +417,13 @@ namespace Poppler {
     {
 	QStringList keys;
 
-	Object info;
 	if ( m_doc->locked )
 	    return QStringList();
 
 	QScopedPointer<XRef> xref(m_doc->doc->getXRef()->copy());
 	if (!xref)
 		return QStringList();
-	xref->getDocInfo(&info);
+	Object info = xref->getDocInfo();
 	if ( !info.isDict() )
 	    return QStringList();
 
@@ -438,7 +434,6 @@ namespace Poppler {
 	    keys.append( QString::fromLatin1(infoDict->getKey(i)) );
 	}
 
-	info.free();
 	return keys;
     }
 
diff --git a/qt5/src/poppler-form.cc b/qt5/src/poppler-form.cc
index 1ccb26ce..6cbceb04 100644
--- a/qt5/src/poppler-form.cc
+++ b/qt5/src/poppler-form.cc
@@ -220,8 +220,8 @@ QString FormFieldButton::caption() const
   if (fwb->getButtonType() == formButtonPush)
   {
     Dict *dict = m_formData->fm->getObj()->getDict();
-    Object obj1;
-    if (dict->lookup("MK", &obj1)->isDict())
+    Object obj1 = dict->lookup("MK");
+    if (obj1.isDict())
     {
       AnnotAppearanceCharacs appearCharacs(obj1.getDict());
       if (appearCharacs.getNormalCaption())
@@ -229,7 +229,6 @@ QString FormFieldButton::caption() const
         ret = UnicodeParsedString(appearCharacs.getNormalCaption());
       }
     }
-    obj1.free();
   }
   else
   {
diff --git a/qt5/src/poppler-optcontent.cc b/qt5/src/poppler-optcontent.cc
index 15ba6503..36b38779 100644
--- a/qt5/src/poppler-optcontent.cc
+++ b/qt5/src/poppler-optcontent.cc
@@ -41,8 +41,7 @@ namespace Poppler
   {
     itemsInGroup.reserve(rbarray->getLength());
     for (int i = 0; i < rbarray->getLength(); ++i) {
-      Object ref;
-      rbarray->getNF( i, &ref );
+      Object ref = rbarray->getNF( i );
       if ( ! ref.isRef() ) {
 	qDebug() << "expected ref, but got:" << ref.getType();
       }
@@ -199,11 +198,9 @@ namespace Poppler
   {
     OptContentItem *lastItem = parentNode;
     for (int i = 0; i < orderArray->getLength(); ++i) {
-      Object orderItem;
-      orderArray->get(i, &orderItem);
+      Object orderItem = orderArray->get(i);
       if ( orderItem.isDict() ) {
-	Object item;
-	orderArray->getNF(i, &item);
+	Object item = orderArray->getNF(i);
 	if (item.isRef() ) {
           OptContentItem *ocItem = m_optContentItems.value(QString::number(item.getRefNum()), 0);
 	  if (ocItem) {
@@ -213,7 +210,6 @@ namespace Poppler
             qDebug() << "could not find group for object" << item.getRefNum();
 	  }
 	}
-	item.free();
       } else if ( (orderItem.isArray()) && (orderItem.arrayGetLength() > 0) ) {
 	parseOrderArray(lastItem, orderItem.getArray());
       } else if ( orderItem.isString() ) {
@@ -226,7 +222,6 @@ namespace Poppler
       } else {
 	qDebug() << "something unexpected";
       }	
-      orderItem.free();
     }
   }
 
@@ -237,8 +232,7 @@ namespace Poppler
     }
     // This is an array of array(s)
     for (int i = 0; i < rBGroupArray->getLength(); ++i) {
-      Object rbObj;
-      rBGroupArray->get(i, &rbObj);
+      Object rbObj = rBGroupArray->get(i);
       if ( ! rbObj.isArray() ) {
 	qDebug() << "expected inner array, got:" << rbObj.getType();
 	return;
@@ -246,7 +240,6 @@ namespace Poppler
       Array *rbarray = rbObj.getArray();
       RadioButtonGroup *rbg = new RadioButtonGroup( this, rbarray );
       m_rbgroups.append( rbg );
-      rbObj.free();
     }
   }
 
diff --git a/qt5/src/poppler-page.cc b/qt5/src/poppler-page.cc
index 4e35a367..7e36cd20 100644
--- a/qt5/src/poppler-page.cc
+++ b/qt5/src/poppler-page.cc
@@ -633,11 +633,10 @@ QList<TextBox*> Page::textList(Rotation rotate) const
 PageTransition *Page::transition() const
 {
   if (!m_page->transition) {
-    Object o;
+    Object o = m_page->page->getTrans();
     PageTransitionParams params;
-    params.dictObj = m_page->page->getTrans(&o);
+    params.dictObj = &o;
     if (params.dictObj->isDict()) m_page->transition = new PageTransition(params);
-    o.free();
   }
   return m_page->transition;
 }
@@ -646,20 +645,15 @@ Link *Page::action( PageAction act ) const
 {
   if ( act == Page::Opening || act == Page::Closing )
   {
-    Object o;
-    m_page->page->getActions(&o);
+    Object o = m_page->page->getActions();
     if (!o.isDict())
     {
-      o.free();
       return 0;
     }
     Dict *dict = o.getDict();
-    Object o2;
     const char *key = act == Page::Opening ? "O" : "C";
-    dict->lookup((char*)key, &o2);
+    Object o2 = dict->lookup((char*)key);
     ::LinkAction *lact = ::LinkAction::parseAction(&o2, m_page->parentDoc->doc->getCatalog()->getBaseURI() );
-    o2.free();
-    o.free();
     Link *popplerLink = NULL;
     if (lact != NULL)
     {
diff --git a/qt5/src/poppler-private.h b/qt5/src/poppler-private.h
index 9afcc843..b1c217ac 100644
--- a/qt5/src/poppler-private.h
+++ b/qt5/src/poppler-private.h
@@ -103,10 +103,8 @@ namespace Poppler {
 	
 	DocumentData(const QByteArray &data, GooString *ownerPassword, GooString *userPassword)
 	    {
-		Object obj;
 		fileContents = data;
-		obj.initNull();
-		MemStream *str = new MemStream((char*)fileContents.data(), 0, fileContents.length(), &obj);
+		MemStream *str = new MemStream((char*)fileContents.data(), 0, fileContents.length(), Object(objNull));
 		init();
 		doc = new PDFDoc(str, ownerPassword, userPassword);
 		delete ownerPassword;
diff --git a/qt5/tests/check_lexer.cpp b/qt5/tests/check_lexer.cpp
index 243a5927..4453e90f 100644
--- a/qt5/tests/check_lexer.cpp
+++ b/qt5/tests/check_lexer.cpp
@@ -13,112 +13,91 @@ private slots:
 void TestLexer::testNumbers()
 {
     char data[] = "0 1 -1 2147483647 -2147483647 2147483648 -2147483648 4294967297 -2147483649 0.1 1.1 -1.1 2147483647.1 -2147483647.1 2147483648.1 -2147483648.1 4294967297.1 -2147483649.1 9223372036854775807 18446744073709551615";
-    Object dummy;
-    MemStream *stream = new MemStream(data, 0, strlen(data), &dummy);
+    MemStream *stream = new MemStream(data, 0, strlen(data), Object(objNull));
     Lexer *lexer = new Lexer(NULL, stream);
     QVERIFY( lexer );
     
     Object obj;
     
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), 0);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), 1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), -1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), 2147483647);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), -2147483647);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt64);
     QCOMPARE(obj.getInt64(), 2147483648ll);
-    obj.free();
       
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt);
     QCOMPARE(obj.getInt(), -2147483647-1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt64);
     QCOMPARE(obj.getInt64(), 4294967297ll);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt64);
     QCOMPARE(obj.getInt64(), -2147483649ll);
-    obj.free();
 
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 0.1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 1.1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), -1.1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 2147483647.1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), -2147483647.1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 2147483648.1);
-    obj.free();
       
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), -2147483648.1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 4294967297.1);
-    obj.free();
-    
-    lexer->getObj(&obj);
+
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), -2147483649.1);
-    obj.free();
 
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objInt64);
     QCOMPARE(obj.getInt64(), 9223372036854775807ll);
-    obj.free();
 
-    lexer->getObj(&obj);
+    obj = lexer->getObj();
     QCOMPARE(obj.getType(), objReal);
     QCOMPARE(obj.getReal(), 18446744073709551616.);
-    obj.free();
 
     delete lexer;
 }
diff --git a/qt5/tests/check_optcontent.cpp b/qt5/tests/check_optcontent.cpp
index cac1b433..32af227e 100644
--- a/qt5/tests/check_optcontent.cpp
+++ b/qt5/tests/check_optcontent.cpp
@@ -101,66 +101,57 @@ void TestOptionalContent::checkIsVisible()
 
     // AnyOn, one element array:
     // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QVERIFY( ocgs->optContentIsVisible( &obj ) );
-    obj.free();
 
     // Same again, looking for any leaks or dubious free()'s
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QVERIFY( ocgs->optContentIsVisible( &obj ) );
-    obj.free();
 
     // AnyOff, one element array:
     // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
-    xref->fetch( 29, 0, &obj );
+    obj = xref->fetch( 29, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOn, one element array:
     // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
-    xref->fetch( 36, 0, &obj );
+    obj = xref->fetch( 36, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
 
     // AllOff, one element array:
     // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
-    xref->fetch( 43, 0, &obj );
+    obj = xref->fetch( 43, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOn, multi-element array:
     // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
-    xref->fetch( 50, 0, &obj );
+    obj = xref->fetch( 50, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOff, multi-element array:
     // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 57, 0, &obj );
+    obj = xref->fetch( 57, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOn, multi-element array:
     // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 64, 0, &obj );
+    obj = xref->fetch( 64, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOff, multi-element array:
     // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 71, 0, &obj );
+    obj = xref->fetch( 71, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     delete doc;
     delete globalParams;
@@ -182,8 +173,7 @@ void TestOptionalContent::checkVisibilitySetting()
 
     // In this test, both Ref(21,0) and Ref(28,0) start On,
     // based on the file settings
-    Object ref21obj;
-    ref21obj.initRef( 21, 0 );
+    Object ref21obj( 21, 0 );
     Ref ref21 = ref21obj.getRef();
     OptionalContentGroup *ocgA = ocgs->findOcgByRef( ref21 );
     QVERIFY( ocgA );
@@ -191,8 +181,7 @@ void TestOptionalContent::checkVisibilitySetting()
     QVERIFY( (ocgA->getName()->cmp("A")) == 0 );
     QCOMPARE( ocgA->getState(), OptionalContentGroup::On );
 
-    Object ref28obj;
-    ref28obj.initRef( 28, 0 );
+    Object ref28obj( 28, 0 );
     Ref ref28 = ref28obj.getRef();
     OptionalContentGroup *ocgB = ocgs->findOcgByRef( ref28 );
     QVERIFY( ocgB );
@@ -205,65 +194,56 @@ void TestOptionalContent::checkVisibilitySetting()
 
     // AnyOn, one element array:
     // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // Same again, looking for any leaks or dubious free()'s
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOff, one element array:
     // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
-    xref->fetch( 29, 0, &obj );
+    obj = xref->fetch( 29, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, one element array:
     // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
-    xref->fetch( 36, 0, &obj );
+    obj = xref->fetch( 36, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOff, one element array:
     // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
-    xref->fetch( 43, 0, &obj );
+    obj = xref->fetch( 43, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOn, multi-element array:
     // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
-    xref->fetch( 50, 0, &obj );
+    obj = xref->fetch( 50, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOff, multi-element array:
     // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 57, 0, &obj );
+    obj = xref->fetch( 57, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, multi-element array:
     // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 64, 0, &obj );
+    obj = xref->fetch( 64, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, multi-element array:
     // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 71, 0, &obj );
+    obj = xref->fetch( 71, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
 
     // Turn the other one off as well (i.e. both are Off)
@@ -271,65 +251,56 @@ void TestOptionalContent::checkVisibilitySetting()
 
     // AnyOn, one element array:
     // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // Same again, looking for any leaks or dubious free()'s
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOff, one element array:
     // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
-    xref->fetch( 29, 0, &obj );
+    obj = xref->fetch( 29, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, one element array:
     // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
-    xref->fetch( 36, 0, &obj );
+    obj = xref->fetch( 36, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, one element array:
     // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
-    xref->fetch( 43, 0, &obj );
+    obj = xref->fetch( 43, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOn, multi-element array:
     // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
-    xref->fetch( 50, 0, &obj );
+    obj = xref->fetch( 50, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AnyOff, multi-element array:
     // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 57, 0, &obj );
+    obj = xref->fetch( 57, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, multi-element array:
     // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 64, 0, &obj );
+    obj = xref->fetch( 64, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, multi-element array:
     // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 71, 0, &obj );
+    obj = xref->fetch( 71, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
 
     // Turn the first one on again (21 is On, 28 is Off)
@@ -337,65 +308,56 @@ void TestOptionalContent::checkVisibilitySetting()
 
     // AnyOn, one element array:
     // 22 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOn>>endobj
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // Same again, looking for any leaks or dubious free()'s
-    xref->fetch( 22, 0, &obj );
+    obj = xref->fetch( 22, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOff, one element array:
     // 29 0 obj<</Type/OCMD/OCGs[21 0 R]/P/AnyOff>>endobj
-    xref->fetch( 29, 0, &obj );
+    obj = xref->fetch( 29, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOn, one element array:
     // 36 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOn>>endobj
-    xref->fetch( 36, 0, &obj );
+    obj = xref->fetch( 36, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, one element array:
     // 43 0 obj<</Type/OCMD/OCGs[28 0 R]/P/AllOff>>endobj
-    xref->fetch( 43, 0, &obj );
+    obj = xref->fetch( 43, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOn, multi-element array:
     // 50 0 obj<</Type/OCMD/OCGs[21 0 R 28 0 R]/P/AnyOn>>endobj
-    xref->fetch( 50, 0, &obj );
+    obj = xref->fetch( 50, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AnyOff, multi-element array:
     // 57 0 obj<</Type/OCMD/P/AnyOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 57, 0, &obj );
+    obj = xref->fetch( 57, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), true );
-    obj.free();
 
     // AllOn, multi-element array:
     // 64 0 obj<</Type/OCMD/P/AllOn/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 64, 0, &obj );
+    obj = xref->fetch( 64, 0);
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     // AllOff, multi-element array:
     // 71 0 obj<</Type/OCMD/P/AllOff/OCGs[21 0 R 28 0 R]>>endobj
-    xref->fetch( 71, 0, &obj );
+    obj = xref->fetch( 71, 0 );
     QVERIFY( obj.isDict() );
     QCOMPARE( ocgs->optContentIsVisible( &obj ), false );
-    obj.free();
 
     delete doc;
     delete globalParams;
diff --git a/test/pdf-fullrewrite.cc b/test/pdf-fullrewrite.cc
index 81083723..1f8fcc4c 100644
--- a/test/pdf-fullrewrite.cc
+++ b/test/pdf-fullrewrite.cc
@@ -124,14 +124,11 @@ static GBool compareDictionaries(Dict *dictA, Dict *dictB)
    * contain the same number of entries, we don't need to check that every key
    * in dictB is also contained in dictA */
   for (int i = 0; i < length; ++i) {
-    Object valA, valB;
     const char *key = dictA->getKey(i);
-    dictA->getValNF(i, &valA);
-    dictB->lookupNF(key, &valB);
+    Object valA = dictA->getValNF(i);
+    Object valB = dictB->lookupNF(key);
     if (!compareObjects(&valA, &valB))
       return gFalse;
-    valA.free();
-    valB.free();
   }
 
   return gTrue;
@@ -200,14 +197,11 @@ static GBool compareObjects(Object *objA, Object *objB)
           return gFalse;
         } else {
           for (int i = 0; i < length; ++i) {
-            Object elemA, elemB;
-            arrayA->getNF(i, &elemA);
-            arrayB->getNF(i, &elemB);
+            Object elemA = arrayA->getNF(i);
+            Object elemB = arrayB->getNF(i);
             if (!compareObjects(&elemA, &elemB)) {
               return gFalse;
             }
-            elemA.free();
-            elemB.free();
           }
           return gTrue;
         }
@@ -348,15 +342,12 @@ static GBool compareDocuments(PDFDoc *origDoc, PDFDoc *newDoc)
     }
 
     // Compare contents
-    Object origObj, newObj;
-    origXRef->fetch(i, origGenNum, &origObj);
-    newXRef->fetch(i, newGenNum, &newObj);
+    Object origObj = origXRef->fetch(i, origGenNum);
+    Object newObj = newXRef->fetch(i, newGenNum);
     if (!compareObjects(&origObj, &newObj)) {
       fprintf(stderr, "XRef entry %u: contents differ\n", i);
       result = gFalse;
     }
-    origObj.free();
-    newObj.free();
   }
 
   return result;
diff --git a/utils/pdfinfo.cc b/utils/pdfinfo.cc
index 9cfdc0ff..0b9e7a92 100644
--- a/utils/pdfinfo.cc
+++ b/utils/pdfinfo.cc
@@ -120,13 +120,13 @@ static const ArgDesc argDesc[] = {
 
 static void printInfoString(Dict *infoDict, const char *key, const char *text,
 			    UnicodeMap *uMap) {
-  Object obj;
   GooString *s1;
   Unicode *u;
   char buf[8];
   int i, n, len;
 
-  if (infoDict->lookup(key, &obj)->isString()) {
+  Object obj = infoDict->lookup(key);
+  if (obj.isString()) {
     fputs(text, stdout);
     s1 = obj.getString();
     len = TextStringToUCS4(s1, &u);
@@ -137,11 +137,9 @@ static void printInfoString(Dict *infoDict, const char *key, const char *text,
     gfree(u);
     fputc('\n', stdout);
   }
-  obj.free();
 }
 
 static void printInfoDate(Dict *infoDict, const char *key, const char *text) {
-  Object obj;
   char *s;
   int year, mon, day, hour, min, sec, tz_hour, tz_minute;
   char tz;
@@ -149,7 +147,8 @@ static void printInfoDate(Dict *infoDict, const char *key, const char *text) {
   time_t time;
   char buf[256];
 
-  if (infoDict->lookup(key, &obj)->isString()) {
+  Object obj = infoDict->lookup(key);
+  if (obj.isString()) {
     fputs(text, stdout);
     s = obj.getString()->getCString();
     // TODO do something with the timezone info
@@ -181,17 +180,16 @@ static void printInfoDate(Dict *infoDict, const char *key, const char *text) {
     }
     fputc('\n', stdout);
   }
-  obj.free();
 }
 
 void printISODate(Dict *infoDict, const char *key, const char *text)
 {
-  Object obj;
   char *s;
   int year, mon, day, hour, min, sec, tz_hour, tz_minute;
   char tz;
 
-  if (infoDict->lookup(key, &obj)->isString()) {
+  Object obj = infoDict->lookup(key);
+  if (obj.isString()) {
     fputs(text, stdout);
     s = obj.getString()->getCString();
     if ( parseDateString( s, &year, &mon, &day, &hour, &min, &sec, &tz, &tz_hour, &tz_minute ) ) {
@@ -208,7 +206,6 @@ void printISODate(Dict *infoDict, const char *key, const char *text)
     }
     fputc('\n', stdout);
   }
-  obj.free();
 }
 
 static void printBox(const char *text, PDFRectangle *box) {
@@ -291,14 +288,13 @@ static void printStruct(const StructElement *element, unsigned indent) {
 
 void printInfo(PDFDoc *doc, UnicodeMap *uMap, long long filesize, GBool multiPage) {
   Page *page;
-  Object info;
   char buf[256];
   double w, h, wISO, hISO;
   int pg, i;
   int r;
 
   // print doc info
-  doc->getDocInfo(&info);
+  Object info = doc->getDocInfo();
   if (info.isDict()) {
     printInfoString(info.getDict(), "Title",        "Title:          ", uMap);
     printInfoString(info.getDict(), "Subject",      "Subject:        ", uMap);
@@ -319,7 +315,6 @@ void printInfo(PDFDoc *doc, UnicodeMap *uMap, long long filesize, GBool multiPag
       printInfoDate(info.getDict(),   "ModDate",      "ModDate:        ");
     }
   }
-  info.free();
 
   // print tagging info
    printf("Tagged:         %s\n",
diff --git a/utils/pdftohtml.cc b/utils/pdftohtml.cc
index 50d89906..5b69ac77 100644
--- a/utils/pdftohtml.cc
+++ b/utils/pdftohtml.cc
@@ -333,7 +333,7 @@ int main(int argc, char *argv[]) {
     goto error;
   }
 
-  doc->getDocInfo(&info);
+  info = doc->getDocInfo();
   if (info.isDict()) {
     docTitle = getInfoString(info.getDict(), "Title");
     author = getInfoString(info.getDict(), "Author");
@@ -343,7 +343,6 @@ int main(int argc, char *argv[]) {
     if( !date )
 	date = getInfoDate(info.getDict(), "CreationDate");
   }
-  info.free();
   if( !docTitle ) docTitle = new GooString(htmlFileName);
 
   if (!singleHtml)
@@ -464,7 +463,8 @@ static GooString* getInfoString(Dict *infoDict, const char *key) {
   // Is rawString UCS2 (as opposed to pdfDocEncoding)
   GBool isUnicode;
 
-  if (infoDict->lookup(key, &obj)->isString()) {
+  obj = infoDict->lookup(key);
+  if (obj.isString()) {
     rawString = obj.getString();
 
     // Convert rawString to unicode
@@ -491,7 +491,6 @@ static GooString* getInfoString(Dict *infoDict, const char *key) {
     delete[] unicodeString;
   }
 
-  obj.free();
   return encodedString;
 }
 
@@ -504,7 +503,8 @@ static GooString* getInfoDate(Dict *infoDict, const char *key) {
   GooString *result = NULL;
   char buf[256];
 
-  if (infoDict->lookup(key, &obj)->isString()) {
+  obj = infoDict->lookup(key);
+  if (obj.isString()) {
     s = obj.getString()->getCString();
     // TODO do something with the timezone info
     if ( parseDateString( s, &year, &mon, &day, &hour, &min, &sec, &tz, &tz_hour, &tz_minute ) ) {
@@ -527,7 +527,6 @@ static GooString* getInfoDate(Dict *infoDict, const char *key) {
       result = new GooString(s);
     }
   }
-  obj.free();
   return result;
 }
 
diff --git a/utils/pdftotext.cc b/utils/pdftotext.cc
index d931a969..39ce72f6 100644
--- a/utils/pdftotext.cc
+++ b/utils/pdftotext.cc
@@ -323,15 +323,14 @@ int main(int argc, char *argv[]) {
     fputs("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">", f);
     fputs("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n", f);
     fputs("<head>\n", f);
-    doc->getDocInfo(&info);
+    info = doc->getDocInfo();
     if (info.isDict()) {
-      Object obj;
-      if (info.getDict()->lookup("Title", &obj)->isString()) {
+      Object obj = info.getDict()->lookup("Title");
+      if (obj.isString()) {
         printInfoString(f, info.getDict(), "Title", "<title>", "</title>\n", uMap);
       } else {
         fputs("<title></title>\n", f);
       }
-      obj.free();
       printInfoString(f, info.getDict(), "Subject",
 		      "<meta name=\"Subject\" content=\"", "\"/>\n", uMap);
       printInfoString(f, info.getDict(), "Keywords",
@@ -347,7 +346,6 @@ int main(int argc, char *argv[]) {
       printInfoDate(f, info.getDict(), "LastModifiedDate",
 		    "<meta name=\"ModDate\" content=\"\"/>\n");
     }
-    info.free();
     fputs("</head>\n", f);
     fputs("<body>\n", f);
     if (!bbox) {
@@ -438,14 +436,14 @@ int main(int argc, char *argv[]) {
 
 static void printInfoString(FILE *f, Dict *infoDict, const char *key,
 			    const char *text1, const char *text2, UnicodeMap *uMap) {
-  Object obj;
   GooString *s1;
   GBool isUnicode;
   Unicode u;
   char buf[9];
   int i, n;
 
-  if (infoDict->lookup(key, &obj)->isString()) {
+  Object obj = infoDict->lookup(key);
+  if (obj.isString()) {
     fputs(text1, f);
     s1 = obj.getString();
     if ((s1->getChar(0) & 0xff) == 0xfe &&
@@ -472,21 +470,17 @@ static void printInfoString(FILE *f, Dict *infoDict, const char *key,
     }
     fputs(text2, f);
   }
-  obj.free();
 }
 
 static void printInfoDate(FILE *f, Dict *infoDict, const char *key, const char *fmt) {
-  Object obj;
-  char *s;
-
-  if (infoDict->lookup(key, &obj)->isString()) {
-    s = obj.getString()->getCString();
+  Object obj = infoDict->lookup(key);
+  if (obj.isString()) {
+    char *s = obj.getString()->getCString();
     if (s[0] == 'D' && s[1] == ':') {
       s += 2;
     }
     fprintf(f, fmt, s);
   }
-  obj.free();
 }
 
 void printLine(FILE *f, TextLine *line) {
diff --git a/utils/pdfunite.cc b/utils/pdfunite.cc
index b1f2be8b..55615e01 100644
--- a/utils/pdfunite.cc
+++ b/utils/pdfunite.cc
@@ -39,149 +39,86 @@ static const ArgDesc argDesc[] = {
 };
 
 void doMergeNameTree(PDFDoc *doc, XRef *srcXRef, XRef *countRef, int oldRefNum, int newRefNum, Dict *srcNameTree, Dict *mergeNameTree, int numOffset) {
-  Object mergeNameArray;
-  Object srcNameArray;
-  mergeNameTree->lookup("Names", &mergeNameArray);
-  srcNameTree->lookup("Names", &srcNameArray);
+  Object mergeNameArray = mergeNameTree->lookup("Names");
+  Object srcNameArray = srcNameTree->lookup("Names");
   if (mergeNameArray.isArray() && srcNameArray.isArray()) {
-    Object *newNameArray = new Object();
-    newNameArray->initArray(srcXRef);
+    Array *newNameArray = new Array(srcXRef);
     int j = 0;
     for (int i = 0; i < srcNameArray.arrayGetLength() - 1; i += 2) {
-      Object key;
-      Object value;
-      srcNameArray.arrayGetNF(i, &key);
-      srcNameArray.arrayGetNF(i + 1, &value);
+      Object key = srcNameArray.arrayGetNF(i);
+      Object value = srcNameArray.arrayGetNF(i + 1);
       if (key.isString() && value.isRef()) {
         while (j < mergeNameArray.arrayGetLength() - 1) {
-          Object mkey;
-          Object mvalue;
-          mergeNameArray.arrayGetNF(j, &mkey);
-          mergeNameArray.arrayGetNF(j + 1, &mvalue);
+          Object mkey = mergeNameArray.arrayGetNF(j);
+          Object mvalue = mergeNameArray.arrayGetNF(j + 1);
           if (mkey.isString() && mvalue.isRef()) {
             if (mkey.getString()->cmp(key.getString()) < 0) {
-              Object *newKey = new Object();
-	      newKey->initString(new GooString(mkey.getString()->getCString()));
-              newNameArray->arrayAdd(newKey);
-              Object *newValue = new Object();
-              newValue->initRef(mvalue.getRef().num + numOffset, mvalue.getRef().gen);
-              newNameArray->arrayAdd(newValue);
-              delete newKey;
-              delete newValue;
+              newNameArray->add(Object(new GooString(mkey.getString()->getCString())));
+              newNameArray->add(Object(mvalue.getRef().num + numOffset, mvalue.getRef().gen));
               j += 2;
             } else if (mkey.getString()->cmp(key.getString()) == 0) {
               j += 2;
             } else {
-              mkey.free();
-              mvalue.free();
               break;
             }
           } else {
             j += 2;
           }
-          mkey.free();
-          mvalue.free();
         }
-        Object *newKey = new Object();
-        newKey->initString(new GooString(key.getString()->getCString()));
-        newNameArray->arrayAdd(newKey);
-        Object *newValue = new Object();
-        newValue->initRef(value.getRef().num, value.getRef().gen);
-        newNameArray->arrayAdd(newValue);
-        delete newKey;
-        delete newValue;
+        newNameArray->add(Object(new GooString(key.getString()->getCString())));
+        newNameArray->add(Object(value.getRef().num, value.getRef().gen));
       }
-      key.free();
-      value.free();
     }
     while (j < mergeNameArray.arrayGetLength() - 1) {
-      Object mkey;
-      Object mvalue;
-      mergeNameArray.arrayGetNF(j, &mkey);
-      mergeNameArray.arrayGetNF(j + 1, &mvalue);
+      Object mkey = mergeNameArray.arrayGetNF(j);
+      Object mvalue = mergeNameArray.arrayGetNF(j + 1);
       if (mkey.isString() && mvalue.isRef()) {
-        Object *newKey = new Object();
-        newKey->initString(new GooString(mkey.getString()->getCString()));
-        newNameArray->arrayAdd(newKey);
-        Object *newValue = new Object();
-        newValue->initRef(mvalue.getRef().num + numOffset, mvalue.getRef().gen);
-        newNameArray->arrayAdd(newValue);
-        delete newKey;
-        delete newValue;
+        newNameArray->add(Object(new GooString(mkey.getString()->getCString())));
+        newNameArray->add(Object(mvalue.getRef().num + numOffset, mvalue.getRef().gen));
       }
       j += 2;
-      mkey.free();
-      mvalue.free();
     }
-    srcNameTree->set("Names", newNameArray);
+    srcNameTree->set("Names", Object(newNameArray));
     doc->markPageObjects(mergeNameTree, srcXRef, countRef, numOffset, oldRefNum, newRefNum);
-    delete newNameArray;
   } else if (srcNameArray.isNull() && mergeNameArray.isArray()) {
-    Object *newNameArray = new Object();
-    newNameArray->initArray(srcXRef);
+    Array *newNameArray = new Array(srcXRef);
     for (int i = 0; i < mergeNameArray.arrayGetLength() - 1; i += 2) {
-      Object key;
-      Object value;
-      mergeNameArray.arrayGetNF(i, &key);
-      mergeNameArray.arrayGetNF(i + 1, &value);
+      Object key = mergeNameArray.arrayGetNF(i);
+      Object value = mergeNameArray.arrayGetNF(i + 1);
       if (key.isString() && value.isRef()) {
-        Object *newKey = new Object();
-	newKey->initString(new GooString(key.getString()->getCString()));
-        newNameArray->arrayAdd(newKey);
-        Object *newValue = new Object();
-        newValue->initRef(value.getRef().num + numOffset, value.getRef().gen);
-        newNameArray->arrayAdd(newValue);
-        delete newKey;
-        delete newValue;
+        newNameArray->add(Object(new GooString(key.getString()->getCString())));
+        newNameArray->add(Object(value.getRef().num + numOffset, value.getRef().gen));
       }
-      key.free();
-      value.free();
     }
-    srcNameTree->add(copyString("Names"), newNameArray);
+    srcNameTree->add(copyString("Names"), Object(newNameArray));
     doc->markPageObjects(mergeNameTree, srcXRef, countRef, numOffset, oldRefNum, newRefNum);
   }
-  mergeNameArray.free();
-  srcNameArray.free();
 }
 
 void doMergeNameDict(PDFDoc *doc, XRef *srcXRef, XRef *countRef, int oldRefNum, int newRefNum, Dict *srcNameDict, Dict *mergeNameDict, int numOffset) {
   for (int i = 0; i < mergeNameDict->getLength(); i++) {
     const char *key = mergeNameDict->getKey(i);
-    Object mergeNameTree;
-    Object srcNameTree;
-    mergeNameDict->lookup(key, &mergeNameTree);
-    srcNameDict->lookup(key, &srcNameTree);
+    Object mergeNameTree = mergeNameDict->lookup(key);
+    Object srcNameTree = srcNameDict->lookup(key);
     if (srcNameTree.isDict() && mergeNameTree.isDict()) {
       doMergeNameTree(doc, srcXRef, countRef, oldRefNum, newRefNum, srcNameTree.getDict(), mergeNameTree.getDict(), numOffset);
     } else if (srcNameTree.isNull() && mergeNameTree.isDict()) {
-      Object *newNameTree = new Object();
-      newNameTree->initDict(srcXRef);
-      doMergeNameTree(doc, srcXRef, countRef, oldRefNum, newRefNum, newNameTree->getDict(), mergeNameTree.getDict(), numOffset);
-      srcNameDict->add(copyString(key), newNameTree);
+      Object newNameTree(new Dict(srcXRef));
+      doMergeNameTree(doc, srcXRef, countRef, oldRefNum, newRefNum, newNameTree.getDict(), mergeNameTree.getDict(), numOffset);
+      srcNameDict->add(copyString(key), std::move(newNameTree));
     }
-    srcNameTree.free();
-    mergeNameTree.free();
   }
 }
 
 void doMergeFormDict(Dict *srcFormDict, Dict *mergeFormDict, int numOffset) {
-  Object srcFields, mergeFields;
-
-  srcFormDict->lookup("Fields", &srcFields);
-  mergeFormDict->lookup("Fields", &mergeFields);
+  Object srcFields = srcFormDict->lookup("Fields");
+  Object mergeFields = mergeFormDict->lookup("Fields");
   if (srcFields.isArray() && mergeFields.isArray()) {
     for (int i = 0; i < mergeFields.arrayGetLength(); i++) {
-      Object value;
-      Object *newValue = new Object();
-      mergeFields.arrayGetNF(i, &value);
-      newValue->initRef(value.getRef().num + numOffset, value.getRef().gen);
-      srcFields.arrayAdd(newValue);
-      value.free();
-      delete newValue;
+      Object value = mergeFields.arrayGetNF(i);
+      srcFields.arrayAdd(Object(value.getRef().num + numOffset, value.getRef().gen));
     }
   }
-  srcFields.free();
-  mergeFields.free();
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -258,58 +195,50 @@ int main (int argc, char *argv[])
 
   // handle OutputIntents, AcroForm, OCProperties & Names
   Object intents;
+  Object names;
   Object afObj;
   Object ocObj;
-  Object names;
   if (docs.size() >= 1) {
-    Object catObj;
-    docs[0]->getXRef()->getCatalog(&catObj);
+    Object catObj = docs[0]->getXRef()->getCatalog();
     Dict *catDict = catObj.getDict();
-    catDict->lookup("OutputIntents", &intents);
-    catDict->lookupNF("AcroForm", &afObj);
+    intents = catDict->lookup("OutputIntents");
+    afObj = catDict->lookupNF("AcroForm");
     Ref *refPage = docs[0]->getCatalog()->getPageRef(1);
     if (!afObj.isNull()) {
       docs[0]->markAcroForm(&afObj, yRef, countRef, 0, refPage->num, refPage->num);
     }
-    catDict->lookupNF("OCProperties", &ocObj);
+    ocObj = catDict->lookupNF("OCProperties");
     if (!ocObj.isNull() && ocObj.isDict()) {
       docs[0]->markPageObjects(ocObj.getDict(), yRef, countRef, 0, refPage->num, refPage->num);
     }
-    catDict->lookup("Names", &names);
+    names = catDict->lookup("Names");
     if (!names.isNull() && names.isDict()) {
       docs[0]->markPageObjects(names.getDict(), yRef, countRef, 0, refPage->num, refPage->num);
     }
     if (intents.isArray() && intents.arrayGetLength() > 0) {
       for (i = 1; i < (int) docs.size(); i++) {
-        Object pagecatObj, pageintents;
-        docs[i]->getXRef()->getCatalog(&pagecatObj);
+        Object pagecatObj = docs[i]->getXRef()->getCatalog();
         Dict *pagecatDict = pagecatObj.getDict();
-        pagecatDict->lookup("OutputIntents", &pageintents);
+        Object pageintents = pagecatDict->lookup("OutputIntents");
         if (pageintents.isArray() && pageintents.arrayGetLength() > 0) {
           for (j = intents.arrayGetLength() - 1; j >= 0; j--) {
-            Object intent;
-            intents.arrayGet(j, &intent, 0);
+            Object intent = intents.arrayGet(j, 0);
             if (intent.isDict()) {
-              Object idf;
-              intent.dictLookup("OutputConditionIdentifier", &idf);
+              Object idf = intent.dictLookup("OutputConditionIdentifier");
               if (idf.isString()) {
                 GooString *gidf = idf.getString();
                 GBool removeIntent = gTrue;
                 for (int k = 0; k < pageintents.arrayGetLength(); k++) {
-                  Object pgintent;
-                  pageintents.arrayGet(k, &pgintent, 0);
+                  Object pgintent = pageintents.arrayGet(k, 0);
                   if (pgintent.isDict()) {
-                    Object pgidf;
-                    pgintent.dictLookup("OutputConditionIdentifier", &pgidf);
+                    Object pgidf = pgintent.dictLookup("OutputConditionIdentifier");
                     if (pgidf.isString()) {
                       GooString *gpgidf = pgidf.getString();
                       if (gpgidf->cmp(gidf) == 0) {
-                        pgidf.free();
                         removeIntent = gFalse;
                         break;
                       }
                     }
-                    pgidf.free();
                   }
                 }
                 if (removeIntent) {
@@ -321,34 +250,26 @@ int main (int argc, char *argv[])
                 intents.arrayRemove(j);
                 error(errSyntaxWarning, -1, "Invalid output intent dict, missing required OutputConditionIdentifier");
               }
-              idf.free();
             } else {
               intents.arrayRemove(j);
             }
-            intent.free();
           }
         } else {
           error(errSyntaxWarning, -1, "Output intents differs, remove them all");
-          intents.free();
           break;
         }
-        pagecatObj.free();
-        pageintents.free();
       }
     }
     if (intents.isArray() && intents.arrayGetLength() > 0) {
       for (j = intents.arrayGetLength() - 1; j >= 0; j--) {
-        Object intent;
-        intents.arrayGet(j, &intent, 0);
+        Object intent = intents.arrayGet(j, 0);
         if (intent.isDict()) {
           docs[0]->markPageObjects(intent.getDict(), yRef, countRef, numOffset, 0, 0);
         } else {
           intents.arrayRemove(j);
         }
-        intent.free();
       }
     }
-    catObj.free();
   }
 
   for (i = 0; i < (int) docs.size(); i++) {
@@ -360,48 +281,38 @@ int main (int argc, char *argv[])
 	    docs[i]->getCatalog()->getPage(j)->getRotate(),
 	    docs[i]->getCatalog()->getPage(j)->getMediaBox(), cropBox);
       Ref *refPage = docs[i]->getCatalog()->getPageRef(j);
-      Object page;
-      docs[i]->getXRef()->fetch(refPage->num, refPage->gen, &page);
+      Object page = docs[i]->getXRef()->fetch(refPage->num, refPage->gen);
       Dict *pageDict = page.getDict();
       Dict *resDict = docs[i]->getCatalog()->getPage(j)->getResourceDict();
       if (resDict) {
-        Object *newResource = new Object();
-        newResource->initDict(resDict);
-        pageDict->set("Resources", newResource);
-        delete newResource;
+        resDict->incRef();
+        pageDict->set("Resources", Object(resDict));
       }
       pages.push_back(std::move(page));
       offsets.push_back(numOffset);
       docs[i]->markPageObjects(pageDict, yRef, countRef, numOffset, refPage->num, refPage->num);
-      Object annotsObj;
-      pageDict->lookupNF("Annots", &annotsObj);
+      Object annotsObj = pageDict->lookupNF("Annots");
       if (!annotsObj.isNull()) {
         docs[i]->markAnnotations(&annotsObj, yRef, countRef, numOffset, refPage->num, refPage->num);
-        annotsObj.free();
       }
     }
-    Object pageCatObj, pageNames, pageForm;
-    docs[i]->getXRef()->getCatalog(&pageCatObj);
+    Object pageCatObj = docs[i]->getXRef()->getCatalog();
     Dict *pageCatDict = pageCatObj.getDict();
-    pageCatDict->lookup("Names", &pageNames);
+    Object pageNames = pageCatDict->lookup("Names");
     if (!pageNames.isNull() && pageNames.isDict()) {
       if (!names.isDict()) {
-        names.free();
-        names.initDict(yRef);
+        names = Object(new Dict(yRef));
       }
       doMergeNameDict(docs[i], yRef, countRef, 0, 0, names.getDict(), pageNames.getDict(), numOffset);
     }
-    pageCatDict->lookup("AcroForm", &pageForm);
+    Object pageForm = pageCatDict->lookup("AcroForm");
     if (i > 0 && !pageForm.isNull() && pageForm.isDict()) {
       if (afObj.isNull()) {
-        pageCatDict->lookupNF("AcroForm", &afObj);
+        afObj = pageCatDict->lookupNF("AcroForm");
       } else if (afObj.isDict()) {
         doMergeFormDict(afObj.getDict(), pageForm.getDict(), numOffset);
       }
     }
-    pageForm.free();
-    pageNames.free();
-    pageCatObj.free();
     objectsCount += docs[i]->writePageObjects(outStr, yRef, numOffset, gTrue);
     numOffset = yRef->getNumObjects() + 1;
   }
@@ -414,33 +325,27 @@ int main (int argc, char *argv[])
   if (intents.isArray() && intents.arrayGetLength() > 0) {
     outStr->printf(" /OutputIntents [");
     for (j = 0; j < intents.arrayGetLength(); j++) {
-      Object intent;
-      intents.arrayGet(j, &intent, 0);
+      Object intent = intents.arrayGet(j, 0);
       if (intent.isDict()) {
         PDFDoc::writeObject(&intent, outStr, yRef, 0, NULL, cryptRC4, 0, 0, 0);
       }
-      intent.free();
     }
     outStr->printf("]");
   }
-  intents.free();
   // insert AcroForm
   if (!afObj.isNull()) {
     outStr->printf(" /AcroForm ");
     PDFDoc::writeObject(&afObj, outStr, yRef, 0, NULL, cryptRC4, 0, 0, 0);
-    afObj.free();
   }
   // insert OCProperties
   if (!ocObj.isNull() && ocObj.isDict()) {
     outStr->printf(" /OCProperties ");
     PDFDoc::writeObject(&ocObj, outStr, yRef, 0, NULL, cryptRC4, 0, 0, 0);
-    ocObj.free();
   }
   // insert Names
   if (!names.isNull() && names.isDict()) {
     outStr->printf(" /Names ");
     PDFDoc::writeObject(&names, outStr, yRef, 0, NULL, cryptRC4, 0, 0, 0);
-    names.free();
   }
   outStr->printf(">>\nendobj\n");
   objectsCount++;
@@ -462,15 +367,13 @@ int main (int argc, char *argv[])
       if (j > 0)
 	outStr->printf(" ");
       const char *key = pageDict->getKey(j);
-      Object value;
-      pageDict->getValNF(j, &value);
+      Object value = pageDict->getValNF(j);
       if (strcmp(key, "Parent") == 0) {
         outStr->printf("/Parent %d 0 R", rootNum + 1);
       } else {
         outStr->printf("/%s ", key);
         PDFDoc::writeObject(&value, outStr, yRef, offsets[i], NULL, cryptRC4, 0, 0, 0);
       }
-      value.free();
     }
     outStr->printf(" >>\nendobj\n");
     objectsCount++;
@@ -490,7 +393,6 @@ int main (int argc, char *argv[])
   fclose(f);
   delete yRef;
   delete countRef;
-  for (j = 0; j < (int) pages.size (); j++) pages[j].free();
   for (i = 0; i < (int) docs.size (); i++) delete docs[i];
   delete globalParams;
   return exitCode;


More information about the poppler mailing list