Add defaulted copy/move constructors/assignment in `Options` classes.
Clean up how `Options` are passed.

As for other types, add copy constructor/assignment except for
`Text{Parse,Print}MessageOptions` which are uncopyable, and add move
constructor/assignment except when copying is equivalent to moving.
This indicates when it is worth using `std::move()` for passing a parameter.

Take `Options` parameters by value in most public functions. Exceptions:

* `CFile{Reader,Writer}Base::Options`: they are movable more efficiently than
  copyable due to a `std::string` member, but the relevant classes do not move
  anything from them, so it is better to accept them by reference.

* `{Fd,riegeli::tensorflow::File}{Reader,Writer}Base::Options`: for consistency.

In private functions, take `Options` parameters by value if they are cheap to
copy or move, otherwise by reference.

PiperOrigin-RevId: 914362870
diff --git a/python/riegeli/bytes/python_reader.h b/python/riegeli/bytes/python_reader.h
index 3c9b7be..e40a942 100644
--- a/python/riegeli/bytes/python_reader.h
+++ b/python/riegeli/bytes/python_reader.h
@@ -63,6 +63,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // If `true`, `PythonReader::Close()` closes the stream.
     //
     // Default: `false`.
diff --git a/python/riegeli/bytes/python_writer.h b/python/riegeli/bytes/python_writer.h
index b1e07fe..7f57062 100644
--- a/python/riegeli/bytes/python_writer.h
+++ b/python/riegeli/bytes/python_writer.h
@@ -56,6 +56,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // If `true`, `PythonWriter::Close()` closes the stream, and
     // `PythonWriter::Flush(flush_type)` flushes the stream even if `flush_type`
     // is `FlushType::kFromObject`.
diff --git a/python/riegeli/records/record_reader.cc b/python/riegeli/records/record_reader.cc
index a9c0554..369ab85 100644
--- a/python/riegeli/records/record_reader.cc
+++ b/python/riegeli/records/record_reader.cc
@@ -366,7 +366,7 @@
     });
   }
 
-  PythonReader python_reader(src_arg, std::move(python_reader_options));
+  PythonReader python_reader(src_arg, python_reader_options);
   PythonUnlocked([&] {
     self->record_reader.emplace(std::move(python_reader),
                                 std::move(record_reader_options));
diff --git a/python/riegeli/records/record_writer.cc b/python/riegeli/records/record_writer.cc
index def5b9f..8cf6cd6 100644
--- a/python/riegeli/records/record_writer.cc
+++ b/python/riegeli/records/record_writer.cc
@@ -331,7 +331,7 @@
         *std::move(serialized_metadata));
   }
 
-  PythonWriter python_writer(dest_arg, std::move(python_writer_options));
+  PythonWriter python_writer(dest_arg, python_writer_options);
   PythonUnlocked([&] {
     self->record_writer.emplace(std::move(python_writer),
                                 std::move(record_writer_options));
diff --git a/riegeli/base/chain_base.h b/riegeli/base/chain_base.h
index fc845da..984c108 100644
--- a/riegeli/base/chain_base.h
+++ b/riegeli/base/chain_base.h
@@ -81,6 +81,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // Expected final size, or `std::nullopt` if unknown. This may improve
     // performance and memory usage.
     //
diff --git a/riegeli/base/recycling_pool.h b/riegeli/base/recycling_pool.h
index 57d9cf6..2e7c1cc 100644
--- a/riegeli/base/recycling_pool.h
+++ b/riegeli/base/recycling_pool.h
@@ -44,7 +44,10 @@
 // Options for `RecyclingPool` and `KeyedRecyclingPool`.
 class RecyclingPoolOptions {
  public:
-  RecyclingPoolOptions() = default;
+  RecyclingPoolOptions() noexcept {}
+
+  RecyclingPoolOptions(const RecyclingPoolOptions& that) = default;
+  RecyclingPoolOptions& operator=(const RecyclingPoolOptions& that) = default;
 
   // Maximum number of objects to keep in a pool.
   //
diff --git a/riegeli/brotli/brotli_reader.h b/riegeli/brotli/brotli_reader.h
index c5651d8..7aa0b8a 100644
--- a/riegeli/brotli/brotli_reader.h
+++ b/riegeli/brotli/brotli_reader.h
@@ -42,6 +42,12 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
+    Options(Options&& that) = default;
+    Options& operator=(Options&& that) = default;
+
     // Shared Brotli dictionary. The same dictionary must have been used
     // for compression. If no dictionary was used for compression, then no
     // dictionary must be supplied for decompression.
diff --git a/riegeli/brotli/brotli_writer.h b/riegeli/brotli/brotli_writer.h
index 8da8a7b..2a5e16e 100644
--- a/riegeli/brotli/brotli_writer.h
+++ b/riegeli/brotli/brotli_writer.h
@@ -48,6 +48,12 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
+    Options(Options&& that) = default;
+    Options& operator=(Options&& that) = default;
+
     // Tunes the tradeoff between compression density and compression speed
     // (higher = better density but slower).
     //
diff --git a/riegeli/bytes/buffer_options.h b/riegeli/bytes/buffer_options.h
index a7a3d48..49377e3 100644
--- a/riegeli/bytes/buffer_options.h
+++ b/riegeli/bytes/buffer_options.h
@@ -34,6 +34,9 @@
  public:
   BufferOptions() noexcept {}
 
+  BufferOptions(const BufferOptions& that) = default;
+  BufferOptions& operator=(const BufferOptions& that) = default;
+
   // Tunes the minimal buffer size, which determines how much data at a time is
   // typically read from the source / written to the destination.
   //
diff --git a/riegeli/bytes/cfile_reader.cc b/riegeli/bytes/cfile_reader.cc
index 84082cc..faf45f0 100644
--- a/riegeli/bytes/cfile_reader.cc
+++ b/riegeli/bytes/cfile_reader.cc
@@ -90,18 +90,18 @@
 
 }  // namespace
 
-void CFileReaderBase::Initialize(FILE* src, Options&& options) {
+void CFileReaderBase::Initialize(FILE* src, const Options& options) {
   RIEGELI_ASSERT_NE(src, nullptr)
       << "Failed precondition of CFileReader: null FILE pointer";
-  InitializePos(src, std::move(options)
+  InitializePos(src, options
 #ifdef _WIN32
-                         ,
+                ,
                 /*mode_was_passed_to_fopen=*/false
 #endif
   );
 }
 
-void CFileReaderBase::InitializePos(FILE* src, Options&& options
+void CFileReaderBase::InitializePos(FILE* src, const Options& options
 #ifdef _WIN32
                                     ,
                                     bool mode_was_passed_to_fopen
@@ -137,7 +137,10 @@
     }
     original_mode_ = original_mode;
   }
-  if (options.assumed_pos() == std::nullopt) {
+#endif  // _WIN32
+  std::optional<Position> assumed_pos = options.assumed_pos();
+#ifdef _WIN32
+  if (assumed_pos == std::nullopt) {
     if (text_mode == 0) {
       const int fd = _fileno(src);
       if (ABSL_PREDICT_FALSE(fd < 0)) {
@@ -155,17 +158,17 @@
         return;
       }
     }
-    if (text_mode != _O_BINARY) options.set_assumed_pos(0);
+    if (text_mode != _O_BINARY) assumed_pos = 0;
   }
 #endif  // _WIN32
-  if (options.assumed_pos() != std::nullopt) {
+  if (assumed_pos != std::nullopt) {
     if (ABSL_PREDICT_FALSE(
-            *options.assumed_pos() >
+            *assumed_pos >
             Position{std::numeric_limits<cfile_internal::Offset>::max()})) {
       FailOverflow();
       return;
     }
-    set_limit_pos(*options.assumed_pos());
+    set_limit_pos(*assumed_pos);
     // `supports_random_access_` is left as `false`.
     random_access_status_ = Global([] {
       return absl::UnimplementedError(
diff --git a/riegeli/bytes/cfile_reader.h b/riegeli/bytes/cfile_reader.h
index ad6d80d..6dd3c7d 100644
--- a/riegeli/bytes/cfile_reader.h
+++ b/riegeli/bytes/cfile_reader.h
@@ -49,6 +49,12 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
+    Options(Options&& that) = default;
+    Options& operator=(Options&& that) = default;
+
     // If `CFileReader` opens a `FILE` with a filename, `mode()` is the second
     // argument of `fopen()` and specifies the open mode, typically "r" (on
     // Windows: "rb").
@@ -203,8 +209,8 @@
 
   void Reset(Closed);
   void Reset(BufferOptions buffer_options, bool growing_source);
-  void Initialize(FILE* src, Options&& options);
-  void InitializePos(FILE* src, Options&& options
+  void Initialize(FILE* src, const Options& options);
+  void InitializePos(FILE* src, const Options& options
 #ifdef _WIN32
                      ,
                      bool mode_was_passed_to_fopen
@@ -260,14 +266,15 @@
   explicit CFileReader(Closed) noexcept : CFileReaderBase(kClosed) {}
 
   // Will read from the `FILE` provided by `src`.
-  explicit CFileReader(Initializer<Src> src, Options options = Options());
+  explicit CFileReader(Initializer<Src> src,
+                       const Options& options = Options());
 
   // Will read from `src`.
   template <
       typename DependentSrc = Src,
       std::enable_if_t<std::is_constructible_v<DependentSrc, FILE*>, int> = 0>
   explicit CFileReader(FILE* src ABSL_ATTRIBUTE_LIFETIME_BOUND,
-                       Options options = Options());
+                       const Options& options = Options());
 
   // Opens a file for reading.
   //
@@ -279,7 +286,8 @@
                 std::conjunction_v<CFileSupportsOpen<DependentSrc>,
                                    std::is_default_constructible<DependentSrc>>,
                 int> = 0>
-  explicit CFileReader(PathInitializer filename, Options options = Options());
+  explicit CFileReader(PathInitializer filename,
+                       const Options& options = Options());
 
   CFileReader(CFileReader&& that) = default;
   CFileReader& operator=(CFileReader&& that) = default;
@@ -288,18 +296,18 @@
   // constructing a temporary `CFileReader` and moving from it.
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Closed);
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Initializer<Src> src,
-                                          Options options = Options());
+                                          const Options& options = Options());
   template <
       typename DependentSrc = Src,
       std::enable_if_t<std::is_constructible_v<DependentSrc, FILE*>, int> = 0>
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(FILE* src,
-                                          Options options = Options());
+                                          const Options& options = Options());
   template <typename DependentSrc = Src,
             std::enable_if_t<std::conjunction_v<CFileSupportsOpen<DependentSrc>,
                                                 SupportsReset<DependentSrc>>,
                              int> = 0>
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(PathInitializer filename,
-                                          Options options = Options());
+                                          const Options& options = Options());
 
   // Returns the object providing and possibly owning the `FILE` being read
   // from. Unchanged by `Close()`.
@@ -325,7 +333,7 @@
  private:
   template <typename DependentSrc = Src,
             std::enable_if_t<CFileSupportsOpen<DependentSrc>::value, int> = 0>
-  void OpenImpl(PathInitializer filename, Options&& options);
+  void OpenImpl(PathInitializer filename, const Options& options);
 
   // The object providing and possibly owning the `FILE` being read from.
   Dependency<CFileHandle, Src> src_;
@@ -333,8 +341,8 @@
 
 explicit CFileReader(Closed) -> CFileReader<DeleteCtad<Closed>>;
 template <typename Src>
-explicit CFileReader(
-    Src&& src, CFileReaderBase::Options options = CFileReaderBase::Options())
+explicit CFileReader(Src&& src, const CFileReaderBase::Options& options =
+                                    CFileReaderBase::Options())
     -> CFileReader<std::conditional_t<
         std::disjunction_v<std::is_convertible<Src&&, FILE*>,
                            std::is_convertible<Src&&, PathInitializer>>,
@@ -393,18 +401,19 @@
 }
 
 template <typename Src>
-inline CFileReader<Src>::CFileReader(Initializer<Src> src, Options options)
+inline CFileReader<Src>::CFileReader(Initializer<Src> src,
+                                     const Options& options)
     : CFileReaderBase(options.buffer_options(), options.growing_source()),
       src_(std::move(src)) {
-  Initialize(src_.get().get(), std::move(options));
+  Initialize(src_.get().get(), options);
 }
 
 template <typename Src>
 template <typename DependentSrc,
           std::enable_if_t<std::is_constructible_v<DependentSrc, FILE*>, int>>
 inline CFileReader<Src>::CFileReader(FILE* src ABSL_ATTRIBUTE_LIFETIME_BOUND,
-                                     Options options)
-    : CFileReader(riegeli::Maker(src), std::move(options)) {}
+                                     const Options& options)
+    : CFileReader(riegeli::Maker(src), options) {}
 
 template <typename Src>
 template <typename DependentSrc,
@@ -412,10 +421,11 @@
               std::conjunction_v<CFileSupportsOpen<DependentSrc>,
                                  std::is_default_constructible<DependentSrc>>,
               int>>
-inline CFileReader<Src>::CFileReader(PathInitializer filename, Options options)
+inline CFileReader<Src>::CFileReader(PathInitializer filename,
+                                     const Options& options)
     : CFileReaderBase(options.buffer_options(), options.growing_source()),
       src_(riegeli::Maker()) {
-  OpenImpl(std::move(filename), std::move(options));
+  OpenImpl(std::move(filename), options);
 }
 
 template <typename Src>
@@ -425,17 +435,18 @@
 }
 
 template <typename Src>
-inline void CFileReader<Src>::Reset(Initializer<Src> src, Options options) {
+inline void CFileReader<Src>::Reset(Initializer<Src> src,
+                                    const Options& options) {
   CFileReaderBase::Reset(options.buffer_options(), options.growing_source());
   src_.Reset(std::move(src));
-  Initialize(src_.get().get(), std::move(options));
+  Initialize(src_.get().get(), options);
 }
 
 template <typename Src>
 template <typename DependentSrc,
           std::enable_if_t<std::is_constructible_v<DependentSrc, FILE*>, int>>
-inline void CFileReader<Src>::Reset(FILE* src, Options options) {
-  Reset(riegeli::Maker(src), std::move(options));
+inline void CFileReader<Src>::Reset(FILE* src, const Options& options) {
+  Reset(riegeli::Maker(src), options);
 }
 
 template <typename Src>
@@ -443,18 +454,20 @@
           std::enable_if_t<std::conjunction_v<CFileSupportsOpen<DependentSrc>,
                                               SupportsReset<DependentSrc>>,
                            int>>
-inline void CFileReader<Src>::Reset(PathInitializer filename, Options options) {
+inline void CFileReader<Src>::Reset(PathInitializer filename,
+                                    const Options& options) {
   // In case `filename` is owned by `src_` and gets invalidated.
   std::string filename_copy = std::move(filename);
   riegeli::Reset(src_.manager());
   CFileReaderBase::Reset(options.buffer_options(), options.growing_source());
-  OpenImpl(std::move(filename_copy), std::move(options));
+  OpenImpl(std::move(filename_copy), options);
 }
 
 template <typename Src>
 template <typename DependentSrc,
           std::enable_if_t<CFileSupportsOpen<DependentSrc>::value, int>>
-void CFileReader<Src>::OpenImpl(PathInitializer filename, Options&& options) {
+void CFileReader<Src>::OpenImpl(PathInitializer filename,
+                                const Options& options) {
   absl::Status status =
       src_.manager().Open(std::move(filename), options.mode());
   if (ABSL_PREDICT_FALSE(!status.ok())) {
@@ -462,9 +475,9 @@
     FailWithoutAnnotation(std::move(status));
     return;
   }
-  InitializePos(src_.get().get(), std::move(options)
+  InitializePos(src_.get().get(), options
 #ifdef _WIN32
-                                      ,
+                ,
                 /*mode_was_passed_to_fopen=*/true
 #endif
   );
diff --git a/riegeli/bytes/cfile_writer.cc b/riegeli/bytes/cfile_writer.cc
index 9b18eff..e32a3fc 100644
--- a/riegeli/bytes/cfile_writer.cc
+++ b/riegeli/bytes/cfile_writer.cc
@@ -62,13 +62,13 @@
 
 namespace riegeli {
 
-void CFileWriterBase::Initialize(FILE* dest, Options&& options) {
+void CFileWriterBase::Initialize(FILE* dest, const Options& options) {
   RIEGELI_ASSERT_NE(dest, nullptr)
       << "Failed precondition of CFileReader: null FILE pointer";
-  InitializePos(dest, std::move(options), /*mode_was_passed_to_fopen=*/false);
+  InitializePos(dest, options, /*mode_was_passed_to_fopen=*/false);
 }
 
-void CFileWriterBase::InitializePos(FILE* dest, Options&& options,
+void CFileWriterBase::InitializePos(FILE* dest, const Options& options,
                                     bool mode_was_passed_to_fopen) {
   RIEGELI_ASSERT_EQ(supports_random_access_, LazyBoolState::kUnknown)
       << "Failed precondition of CFileWriterBase::InitializePos(): "
@@ -115,7 +115,10 @@
     }
     original_mode_ = original_mode;
   }
-  if (options.assumed_pos() == std::nullopt) {
+#endif  // _WIN32
+  std::optional<Position> assumed_pos = options.assumed_pos();
+#ifdef _WIN32
+  if (assumed_pos == std::nullopt) {
     if (text_mode == 0) {
       const int fd = _fileno(dest);
       if (ABSL_PREDICT_FALSE(fd < 0)) {
@@ -133,17 +136,17 @@
         return;
       }
     }
-    if (text_mode != _O_BINARY) options.set_assumed_pos(0);
+    if (text_mode != _O_BINARY) assumed_pos = 0;
   }
 #endif  // _WIN32
-  if (options.assumed_pos() != std::nullopt) {
+  if (assumed_pos != std::nullopt) {
     if (ABSL_PREDICT_FALSE(
-            *options.assumed_pos() >
+            *assumed_pos >
             Position{std::numeric_limits<cfile_internal::Offset>::max()})) {
       FailOverflow();
       return;
     }
-    set_start_pos(*options.assumed_pos());
+    set_start_pos(*assumed_pos);
     supports_random_access_ = LazyBoolState::kFalse;
     supports_read_mode_ = LazyBoolState::kFalse;
     random_access_status_ = Global([] {
diff --git a/riegeli/bytes/cfile_writer.h b/riegeli/bytes/cfile_writer.h
index dfa34ab..65277da 100644
--- a/riegeli/bytes/cfile_writer.h
+++ b/riegeli/bytes/cfile_writer.h
@@ -55,6 +55,12 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
+    Options(Options&& that) = default;
+    Options& operator=(Options&& that) = default;
+
     // If `CFileWriter` opens a `FILE` with a filename, `mode()` is the second
     // argument of `fopen()` and specifies the open mode, typically "w" or "a"
     // (on Windows: "wb" or "ab").
@@ -284,8 +290,8 @@
 
   void Reset(Closed);
   void Reset(BufferOptions buffer_options);
-  void Initialize(FILE* dest, Options&& options);
-  void InitializePos(FILE* dest, Options&& options,
+  void Initialize(FILE* dest, const Options& options);
+  void InitializePos(FILE* dest, const Options& options,
                      bool mode_was_passed_to_fopen);
   ABSL_ATTRIBUTE_COLD bool FailOperation(absl::string_view operation);
 
@@ -362,14 +368,15 @@
   explicit CFileWriter(Closed) noexcept : CFileWriterBase(kClosed) {}
 
   // Will write to the `FILE` provided by `dest`.
-  explicit CFileWriter(Initializer<Dest> dest, Options options = Options());
+  explicit CFileWriter(Initializer<Dest> dest,
+                       const Options& options = Options());
 
   // Will write to `dest`.
   template <
       typename DependentDest = Dest,
       std::enable_if_t<std::is_constructible_v<DependentDest, FILE*>, int> = 0>
   explicit CFileWriter(FILE* dest ABSL_ATTRIBUTE_LIFETIME_BOUND,
-                       Options options = Options());
+                       const Options& options = Options());
 
   // Opens a file for writing.
   //
@@ -381,7 +388,8 @@
                                  CFileSupportsOpen<DependentDest>,
                                  std::is_default_constructible<DependentDest>>,
                              int> = 0>
-  explicit CFileWriter(PathInitializer filename, Options options = Options());
+  explicit CFileWriter(PathInitializer filename,
+                       const Options& options = Options());
 
   CFileWriter(CFileWriter&& that) = default;
   CFileWriter& operator=(CFileWriter&& that) = default;
@@ -390,19 +398,19 @@
   // constructing a temporary `CFileWriter` and moving from it.
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Closed);
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Initializer<Dest> dest,
-                                          Options options = Options());
+                                          const Options& options = Options());
   template <
       typename DependentDest = Dest,
       std::enable_if_t<std::is_constructible_v<DependentDest, FILE*>, int> = 0>
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(FILE* dest,
-                                          Options options = Options());
+                                          const Options& options = Options());
   template <
       typename DependentDest = Dest,
       std::enable_if_t<std::conjunction_v<CFileSupportsOpen<DependentDest>,
                                           SupportsReset<DependentDest>>,
                        int> = 0>
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(PathInitializer filename,
-                                          Options options = Options());
+                                          const Options& options = Options());
 
   // Returns the object providing and possibly owning the `FILE` being written
   // to. Unchanged by `Close()`.
@@ -429,7 +437,7 @@
  private:
   template <typename DependentDest = Dest,
             std::enable_if_t<CFileSupportsOpen<DependentDest>::value, int> = 0>
-  void OpenImpl(PathInitializer filename, Options&& options);
+  void OpenImpl(PathInitializer filename, const Options& options);
 
   // The object providing and possibly owning the `FILE` being written to.
   Dependency<CFileHandle, Dest> dest_;
@@ -437,8 +445,8 @@
 
 explicit CFileWriter(Closed) -> CFileWriter<DeleteCtad<Closed>>;
 template <typename Dest>
-explicit CFileWriter(
-    Dest&& dest, CFileWriterBase::Options options = CFileWriterBase::Options())
+explicit CFileWriter(Dest&& dest, const CFileWriterBase::Options& options =
+                                      CFileWriterBase::Options())
     -> CFileWriter<std::conditional_t<
         std::disjunction_v<std::is_convertible<Dest&&, FILE*>,
                            std::is_convertible<Dest&&, PathInitializer>>,
@@ -508,17 +516,18 @@
 }
 
 template <typename Dest>
-inline CFileWriter<Dest>::CFileWriter(Initializer<Dest> dest, Options options)
+inline CFileWriter<Dest>::CFileWriter(Initializer<Dest> dest,
+                                      const Options& options)
     : CFileWriterBase(options.buffer_options()), dest_(std::move(dest)) {
-  Initialize(dest_.get().get(), std::move(options));
+  Initialize(dest_.get().get(), options);
 }
 
 template <typename Dest>
 template <typename DependentDest,
           std::enable_if_t<std::is_constructible_v<DependentDest, FILE*>, int>>
 inline CFileWriter<Dest>::CFileWriter(FILE* dest ABSL_ATTRIBUTE_LIFETIME_BOUND,
-                                      Options options)
-    : CFileWriter(riegeli::Maker(dest), std::move(options)) {}
+                                      const Options& options)
+    : CFileWriter(riegeli::Maker(dest), options) {}
 
 template <typename Dest>
 template <typename DependentDest,
@@ -526,9 +535,10 @@
               std::conjunction_v<CFileSupportsOpen<DependentDest>,
                                  std::is_default_constructible<DependentDest>>,
               int>>
-inline CFileWriter<Dest>::CFileWriter(PathInitializer filename, Options options)
+inline CFileWriter<Dest>::CFileWriter(PathInitializer filename,
+                                      const Options& options)
     : CFileWriterBase(options.buffer_options()), dest_(riegeli::Maker()) {
-  OpenImpl(std::move(filename), std::move(options));
+  OpenImpl(std::move(filename), options);
 }
 
 template <typename Dest>
@@ -538,17 +548,18 @@
 }
 
 template <typename Dest>
-inline void CFileWriter<Dest>::Reset(Initializer<Dest> dest, Options options) {
+inline void CFileWriter<Dest>::Reset(Initializer<Dest> dest,
+                                     const Options& options) {
   CFileWriterBase::Reset(options.buffer_options());
   dest_.Reset(std::move(dest));
-  Initialize(dest_.get().get(), std::move(options));
+  Initialize(dest_.get().get(), options);
 }
 
 template <typename Dest>
 template <typename DependentDest,
           std::enable_if_t<std::is_constructible_v<DependentDest, FILE*>, int>>
-inline void CFileWriter<Dest>::Reset(FILE* dest, Options options) {
-  Reset(riegeli::Maker(dest), std::move(options));
+inline void CFileWriter<Dest>::Reset(FILE* dest, const Options& options) {
+  Reset(riegeli::Maker(dest), options);
 }
 
 template <typename Dest>
@@ -557,18 +568,19 @@
                                               SupportsReset<DependentDest>>,
                            int>>
 inline void CFileWriter<Dest>::Reset(PathInitializer filename,
-                                     Options options) {
+                                     const Options& options) {
   // In case `filename` is owned by `dest_` and gets invalidated.
   std::string filename_copy = std::move(filename);
   riegeli::Reset(dest_.manager());
   CFileWriterBase::Reset(options.buffer_options());
-  OpenImpl(std::move(filename_copy), std::move(options));
+  OpenImpl(std::move(filename_copy), options);
 }
 
 template <typename Dest>
 template <typename DependentDest,
           std::enable_if_t<CFileSupportsOpen<DependentDest>::value, int>>
-void CFileWriter<Dest>::OpenImpl(PathInitializer filename, Options&& options) {
+void CFileWriter<Dest>::OpenImpl(PathInitializer filename,
+                                 const Options& options) {
   absl::Status status =
       dest_.manager().Open(std::move(filename), options.mode());
   if (ABSL_PREDICT_FALSE(!status.ok())) {
@@ -576,7 +588,7 @@
     FailWithoutAnnotation(std::move(status));
     return;
   }
-  InitializePos(dest_.get().get(), std::move(options),
+  InitializePos(dest_.get().get(), options,
                 /*mode_was_passed_to_fopen=*/true);
 }
 
diff --git a/riegeli/bytes/chain_backward_writer.h b/riegeli/bytes/chain_backward_writer.h
index 37a5a48..0114a1d 100644
--- a/riegeli/bytes/chain_backward_writer.h
+++ b/riegeli/bytes/chain_backward_writer.h
@@ -48,6 +48,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // If `false`, replaces existing contents of the destination, clearing it
     // first.
     //
@@ -126,13 +129,13 @@
  protected:
   explicit ChainBackwardWriterBase(Closed) noexcept : BackwardWriter(kClosed) {}
 
-  explicit ChainBackwardWriterBase(const Options& options);
+  explicit ChainBackwardWriterBase(Options options);
 
   ChainBackwardWriterBase(ChainBackwardWriterBase&& that) noexcept;
   ChainBackwardWriterBase& operator=(ChainBackwardWriterBase&& that) noexcept;
 
   void Reset(Closed);
-  void Reset(const Options& options);
+  void Reset(Options options);
   void Initialize(Chain* dest, bool prepend);
 
   void Done() override;
@@ -248,7 +251,7 @@
 
 // Implementation details follow.
 
-inline ChainBackwardWriterBase::ChainBackwardWriterBase(const Options& options)
+inline ChainBackwardWriterBase::ChainBackwardWriterBase(Options options)
     : options_(Chain::Options()
                    .set_min_block_size(options.min_block_size())
                    .set_max_block_size(options.max_block_size())) {}
@@ -270,7 +273,7 @@
   options_ = Chain::Options();
 }
 
-inline void ChainBackwardWriterBase::Reset(const Options& options) {
+inline void ChainBackwardWriterBase::Reset(Options options) {
   BackwardWriter::Reset();
   options_ = Chain::Options()
                  .set_min_block_size(options.min_block_size())
@@ -329,7 +332,7 @@
 template <typename DependentDest,
           std::enable_if_t<std::is_same_v<DependentDest, Chain>, int>>
 inline ChainBackwardWriter<Dest>::ChainBackwardWriter(Options options)
-    : ChainBackwardWriter(riegeli::Maker(), std::move(options)) {}
+    : ChainBackwardWriter(riegeli::Maker(), options) {}
 
 template <typename Dest>
 inline void ChainBackwardWriter<Dest>::Reset(Closed) {
@@ -349,7 +352,7 @@
 template <typename DependentDest,
           std::enable_if_t<std::is_same_v<DependentDest, Chain>, int>>
 inline void ChainBackwardWriter<Dest>::Reset(Options options) {
-  Reset(riegeli::Maker(), std::move(options));
+  Reset(riegeli::Maker(), options);
 }
 
 }  // namespace riegeli
diff --git a/riegeli/bytes/chain_writer.h b/riegeli/bytes/chain_writer.h
index eacdaf1..0740f1a 100644
--- a/riegeli/bytes/chain_writer.h
+++ b/riegeli/bytes/chain_writer.h
@@ -53,6 +53,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // If `false`, replaces existing contents of the destination, clearing it
     // first.
     //
@@ -135,13 +138,13 @@
  protected:
   explicit ChainWriterBase(Closed) noexcept : Writer(kClosed) {}
 
-  explicit ChainWriterBase(const Options& options);
+  explicit ChainWriterBase(Options options);
 
   ChainWriterBase(ChainWriterBase&& that) noexcept;
   ChainWriterBase& operator=(ChainWriterBase&& that) noexcept;
 
   void Reset(Closed);
-  void Reset(const Options& options);
+  void Reset(Options options);
   void Initialize(Chain* dest, bool append);
 
   void Done() override;
@@ -304,7 +307,7 @@
 
 // Implementation details follow.
 
-inline ChainWriterBase::ChainWriterBase(const Options& options)
+inline ChainWriterBase::ChainWriterBase(Options options)
     : options_(Chain::Options()
                    .set_min_block_size(options.min_block_size())
                    .set_max_block_size(options.max_block_size())) {}
@@ -331,7 +334,7 @@
   associated_reader_.Reset();
 }
 
-inline void ChainWriterBase::Reset(const Options& options) {
+inline void ChainWriterBase::Reset(Options options) {
   Writer::Reset();
   options_ = Chain::Options()
                  .set_min_block_size(options.min_block_size())
@@ -394,7 +397,7 @@
 template <typename DependentDest,
           std::enable_if_t<std::is_same_v<DependentDest, Chain>, int>>
 inline ChainWriter<Dest>::ChainWriter(Options options)
-    : ChainWriter(riegeli::Maker(), std::move(options)) {}
+    : ChainWriter(riegeli::Maker(), options) {}
 
 template <typename Dest>
 inline void ChainWriter<Dest>::Reset(Closed) {
@@ -413,7 +416,7 @@
 template <typename DependentDest,
           std::enable_if_t<std::is_same_v<DependentDest, Chain>, int>>
 inline void ChainWriter<Dest>::Reset(Options options) {
-  Reset(riegeli::Maker(), std::move(options));
+  Reset(riegeli::Maker(), options);
 }
 
 }  // namespace riegeli
diff --git a/riegeli/bytes/cord_backward_writer.h b/riegeli/bytes/cord_backward_writer.h
index 31d413c..d2b3b7d 100644
--- a/riegeli/bytes/cord_backward_writer.h
+++ b/riegeli/bytes/cord_backward_writer.h
@@ -48,6 +48,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // If `false`, replaces existing contents of the destination, clearing it
     // first.
     //
@@ -127,13 +130,13 @@
  protected:
   explicit CordBackwardWriterBase(Closed) noexcept : BackwardWriter(kClosed) {}
 
-  explicit CordBackwardWriterBase(const Options& options);
+  explicit CordBackwardWriterBase(Options options);
 
   CordBackwardWriterBase(CordBackwardWriterBase&& that) noexcept;
   CordBackwardWriterBase& operator=(CordBackwardWriterBase&& that) noexcept;
 
   void Reset(Closed);
-  void Reset(const Options& options);
+  void Reset(Options options);
   void Initialize(absl::Cord* dest, bool prepend);
 
   void Done() override;
@@ -259,7 +262,7 @@
 
 // Implementation details follow.
 
-inline CordBackwardWriterBase::CordBackwardWriterBase(const Options& options)
+inline CordBackwardWriterBase::CordBackwardWriterBase(Options options)
     : min_block_size_(IntCast<uint32_t>(options.min_block_size())),
       max_block_size_(IntCast<uint32_t>(options.max_block_size())) {}
 
@@ -294,7 +297,7 @@
   buffer_ = Buffer();
 }
 
-inline void CordBackwardWriterBase::Reset(const Options& options) {
+inline void CordBackwardWriterBase::Reset(Options options) {
   BackwardWriter::Reset();
   size_hint_ = std::nullopt;
   min_block_size_ = IntCast<uint32_t>(options.min_block_size());
@@ -340,7 +343,7 @@
 template <typename DependentDest,
           std::enable_if_t<std::is_same_v<DependentDest, absl::Cord>, int>>
 inline CordBackwardWriter<Dest>::CordBackwardWriter(Options options)
-    : CordBackwardWriter(riegeli::Maker(), std::move(options)) {}
+    : CordBackwardWriter(riegeli::Maker(), options) {}
 
 template <typename Dest>
 inline void CordBackwardWriter<Dest>::Reset(Closed) {
@@ -360,7 +363,7 @@
 template <typename DependentDest,
           std::enable_if_t<std::is_same_v<DependentDest, absl::Cord>, int>>
 inline void CordBackwardWriter<Dest>::Reset(Options options) {
-  Reset(riegeli::Maker(), std::move(options));
+  Reset(riegeli::Maker(), options);
 }
 
 }  // namespace riegeli
diff --git a/riegeli/bytes/cord_writer.h b/riegeli/bytes/cord_writer.h
index 3dc29aa..af62234 100644
--- a/riegeli/bytes/cord_writer.h
+++ b/riegeli/bytes/cord_writer.h
@@ -54,6 +54,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // If `false`, replaces existing contents of the destination, clearing it
     // first.
     //
@@ -137,13 +140,13 @@
  protected:
   explicit CordWriterBase(Closed) noexcept : Writer(kClosed) {}
 
-  explicit CordWriterBase(const Options& options);
+  explicit CordWriterBase(Options options);
 
   CordWriterBase(CordWriterBase&& that) noexcept;
   CordWriterBase& operator=(CordWriterBase&& that) noexcept;
 
   void Reset(Closed);
-  void Reset(const Options& options);
+  void Reset(Options options);
   void Initialize(absl::Cord* dest, bool append);
 
   void Done() override;
@@ -315,7 +318,7 @@
 
 // Implementation details follow.
 
-inline CordWriterBase::CordWriterBase(const Options& options)
+inline CordWriterBase::CordWriterBase(Options options)
     : min_block_size_(IntCast<uint32_t>(options.min_block_size())),
       max_block_size_(IntCast<uint32_t>(options.max_block_size())) {}
 
@@ -355,7 +358,7 @@
   associated_reader_.Reset();
 }
 
-inline void CordWriterBase::Reset(const Options& options) {
+inline void CordWriterBase::Reset(Options options) {
   Writer::Reset();
   size_hint_ = std::nullopt;
   min_block_size_ = IntCast<uint32_t>(options.min_block_size());
@@ -411,7 +414,7 @@
 template <typename DependentDest,
           std::enable_if_t<std::is_same_v<DependentDest, absl::Cord>, int>>
 inline CordWriter<Dest>::CordWriter(Options options)
-    : CordWriter(riegeli::Maker(), std::move(options)) {}
+    : CordWriter(riegeli::Maker(), options) {}
 
 template <typename Dest>
 inline void CordWriter<Dest>::Reset(Closed) {
@@ -430,7 +433,7 @@
 template <typename DependentDest,
           std::enable_if_t<std::is_same_v<DependentDest, absl::Cord>, int>>
 inline void CordWriter<Dest>::Reset(Options options) {
-  Reset(riegeli::Maker(), std::move(options));
+  Reset(riegeli::Maker(), options);
 }
 
 }  // namespace riegeli
diff --git a/riegeli/bytes/fd_mmap_reader.cc b/riegeli/bytes/fd_mmap_reader.cc
index 2d736e0..0955c7e 100644
--- a/riegeli/bytes/fd_mmap_reader.cc
+++ b/riegeli/bytes/fd_mmap_reader.cc
@@ -193,13 +193,13 @@
 
 }  // namespace
 
-void FdMMapReaderBase::Initialize(int src, Options&& options) {
+void FdMMapReaderBase::Initialize(int src, const Options& options) {
   RIEGELI_ASSERT_GE(src, 0)
       << "Failed precondition of FdMMapReader: negative file descriptor";
-  InitializePos(src, std::move(options));
+  InitializePos(src, options);
 }
 
-void FdMMapReaderBase::InitializePos(int src, Options&& options) {
+void FdMMapReaderBase::InitializePos(int src, const Options& options) {
   Position initial_pos;
   if (options.independent_pos() != std::nullopt) {
     initial_pos = *options.independent_pos();
diff --git a/riegeli/bytes/fd_mmap_reader.h b/riegeli/bytes/fd_mmap_reader.h
index d5e77b9..76edda8 100644
--- a/riegeli/bytes/fd_mmap_reader.h
+++ b/riegeli/bytes/fd_mmap_reader.h
@@ -50,6 +50,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // If `FdMMapReader` opens a fd with a filename, `mode()` is the second
     // argument of `open()` (on Windows: `_open()`) and specifies the open mode
     // and flags, typically `O_RDONLY` (on Windows: `_O_RDONLY | _O_BINARY`).
@@ -185,8 +188,8 @@
 
   void Reset(Closed);
   void Reset();
-  void Initialize(int src, Options&& options);
-  void InitializePos(int src, Options&& options);
+  void Initialize(int src, const Options& options);
+  void InitializePos(int src, const Options& options);
   ABSL_ATTRIBUTE_COLD bool FailOperation(absl::string_view operation);
 #ifdef _WIN32
   ABSL_ATTRIBUTE_COLD bool FailWindowsOperation(absl::string_view operation);
@@ -241,14 +244,15 @@
   explicit FdMMapReader(Closed) noexcept : FdMMapReaderBase(kClosed) {}
 
   // Will read from the fd provided by `src`.
-  explicit FdMMapReader(Initializer<Src> src, Options options = Options());
+  explicit FdMMapReader(Initializer<Src> src,
+                        const Options& options = Options());
 
   // Will read from `src`.
   template <
       typename DependentSrc = Src,
       std::enable_if_t<std::is_constructible_v<DependentSrc, int>, int> = 0>
   explicit FdMMapReader(int src ABSL_ATTRIBUTE_LIFETIME_BOUND,
-                        Options options = Options());
+                        const Options& options = Options());
 
   // Opens a file for reading.
   //
@@ -260,7 +264,8 @@
                 std::conjunction_v<FdSupportsOpen<DependentSrc>,
                                    std::is_default_constructible<DependentSrc>>,
                 int> = 0>
-  explicit FdMMapReader(PathInitializer filename, Options options = Options());
+  explicit FdMMapReader(PathInitializer filename,
+                        const Options& options = Options());
 
   // Opens a file for reading, with the filename interpreted relatively to the
   // directory specified by an existing fd.
@@ -274,7 +279,7 @@
                                    std::is_default_constructible<DependentSrc>>,
                 int> = 0>
   explicit FdMMapReader(UnownedFd dir_fd, PathRef filename,
-                        Options options = Options());
+                        const Options& options = Options());
 
   FdMMapReader(FdMMapReader&& that) = default;
   FdMMapReader& operator=(FdMMapReader&& that) = default;
@@ -283,24 +288,25 @@
   // constructing a temporary `FdMMapReader` and moving from it.
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Closed);
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Initializer<Src> src,
-                                          Options options = Options());
+                                          const Options& options = Options());
   template <
       typename DependentSrc = Src,
       std::enable_if_t<std::is_constructible_v<DependentSrc, int>, int> = 0>
-  ABSL_ATTRIBUTE_REINITIALIZES void Reset(int src, Options options = Options());
+  ABSL_ATTRIBUTE_REINITIALIZES void Reset(int src,
+                                          const Options& options = Options());
   template <typename DependentSrc = Src,
             std::enable_if_t<std::conjunction_v<FdSupportsOpen<DependentSrc>,
                                                 SupportsReset<DependentSrc>>,
                              int> = 0>
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(PathInitializer filename,
-                                          Options options = Options());
+                                          const Options& options = Options());
   template <typename DependentSrc = Src,
             std::enable_if_t<std::conjunction_v<FdSupportsOpenAt<DependentSrc>,
                                                 SupportsReset<DependentSrc>>,
                              int> = 0>
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(UnownedFd dir_fd,
                                           PathInitializer filename,
-                                          Options options = Options());
+                                          const Options& options = Options());
 
   // Returns the object providing and possibly owning the fd being read from.
   // Unchanged by `Close()`.
@@ -328,10 +334,10 @@
 
   template <typename DependentSrc = Src,
             std::enable_if_t<FdSupportsOpen<DependentSrc>::value, int> = 0>
-  void OpenImpl(PathInitializer filename, Options&& options);
+  void OpenImpl(PathInitializer filename, const Options& options);
   template <typename DependentSrc = Src,
             std::enable_if_t<FdSupportsOpenAt<DependentSrc>::value, int> = 0>
-  void OpenAtImpl(UnownedFd dir_fd, PathRef filename, Options&& options);
+  void OpenAtImpl(UnownedFd dir_fd, PathRef filename, const Options& options);
 
   template <typename DependentSrc = Src,
             std::enable_if_t<std::is_same_v<DependentSrc, UnownedFd>, int> = 0>
@@ -343,14 +349,14 @@
 
 explicit FdMMapReader(Closed) -> FdMMapReader<DeleteCtad<Closed>>;
 template <typename Src>
-explicit FdMMapReader(
-    Src&& src, FdMMapReaderBase::Options options = FdMMapReaderBase::Options())
+explicit FdMMapReader(Src&& src, const FdMMapReaderBase::Options& options =
+                                     FdMMapReaderBase::Options())
     -> FdMMapReader<std::conditional_t<
         std::disjunction_v<std::is_convertible<Src&&, int>,
                            std::is_convertible<Src&&, absl::string_view>>,
         OwnedFd, TargetT<Src>>>;
 explicit FdMMapReader(UnownedFd dir_fd, PathRef filename,
-                      FdMMapReaderBase::Options options =
+                      const FdMMapReaderBase::Options& options =
                           FdMMapReaderBase::Options()) -> FdMMapReader<OwnedFd>;
 
 // Implementation details follow.
@@ -384,17 +390,18 @@
 }
 
 template <typename Src>
-inline FdMMapReader<Src>::FdMMapReader(Initializer<Src> src, Options options)
+inline FdMMapReader<Src>::FdMMapReader(Initializer<Src> src,
+                                       const Options& options)
     : src_(std::move(src)) {
-  Initialize(src_.get().get(), std::move(options));
+  Initialize(src_.get().get(), options);
 }
 
 template <typename Src>
 template <typename DependentSrc,
           std::enable_if_t<std::is_constructible_v<DependentSrc, int>, int>>
 inline FdMMapReader<Src>::FdMMapReader(int src ABSL_ATTRIBUTE_LIFETIME_BOUND,
-                                       Options options)
-    : FdMMapReader(riegeli::Maker(src), std::move(options)) {}
+                                       const Options& options)
+    : FdMMapReader(riegeli::Maker(src), options) {}
 
 template <typename Src>
 template <typename DependentSrc,
@@ -403,9 +410,9 @@
                                  std::is_default_constructible<DependentSrc>>,
               int>>
 inline FdMMapReader<Src>::FdMMapReader(PathInitializer filename,
-                                       Options options)
+                                       const Options& options)
     : src_(riegeli::Maker()) {
-  OpenImpl(std::move(filename), std::move(options));
+  OpenImpl(std::move(filename), options);
 }
 
 template <typename Src>
@@ -415,9 +422,9 @@
                                  std::is_default_constructible<DependentSrc>>,
               int>>
 inline FdMMapReader<Src>::FdMMapReader(UnownedFd dir_fd, PathRef filename,
-                                       Options options)
+                                       const Options& options)
     : src_(riegeli::Maker()) {
-  OpenAtImpl(std::move(dir_fd), filename, std::move(options));
+  OpenAtImpl(std::move(dir_fd), filename, options);
 }
 
 template <typename Src>
@@ -427,17 +434,18 @@
 }
 
 template <typename Src>
-inline void FdMMapReader<Src>::Reset(Initializer<Src> src, Options options) {
+inline void FdMMapReader<Src>::Reset(Initializer<Src> src,
+                                     const Options& options) {
   FdMMapReaderBase::Reset();
   src_.Reset(std::move(src));
-  Initialize(src_.get().get(), std::move(options));
+  Initialize(src_.get().get(), options);
 }
 
 template <typename Src>
 template <typename DependentSrc,
           std::enable_if_t<std::is_constructible_v<DependentSrc, int>, int>>
-inline void FdMMapReader<Src>::Reset(int src, Options options) {
-  Reset(riegeli::Maker(src), std::move(options));
+inline void FdMMapReader<Src>::Reset(int src, const Options& options) {
+  Reset(riegeli::Maker(src), options);
 }
 
 template <typename Src>
@@ -446,12 +454,12 @@
                                               SupportsReset<DependentSrc>>,
                            int>>
 inline void FdMMapReader<Src>::Reset(PathInitializer filename,
-                                     Options options) {
+                                     const Options& options) {
   // In case `filename` is owned by `src_` and gets invalidated.
   std::string filename_copy = std::move(filename);
   riegeli::Reset(src_.manager());
   FdMMapReaderBase::Reset();
-  OpenImpl(std::move(filename_copy), std::move(options));
+  OpenImpl(std::move(filename_copy), options);
 }
 
 template <typename Src>
@@ -460,18 +468,19 @@
                                               SupportsReset<DependentSrc>>,
                            int>>
 inline void FdMMapReader<Src>::Reset(UnownedFd dir_fd, PathInitializer filename,
-                                     Options options) {
+                                     const Options& options) {
   // In case `filename` is owned by `src_` and gets invalidated.
   std::string filename_copy = std::move(filename);
   riegeli::Reset(src_.manager());
   FdMMapReaderBase::Reset();
-  OpenAtImpl(dir_fd, filename_copy, std::move(options));
+  OpenAtImpl(dir_fd, filename_copy, options);
 }
 
 template <typename Src>
 template <typename DependentSrc,
           std::enable_if_t<FdSupportsOpen<DependentSrc>::value, int>>
-void FdMMapReader<Src>::OpenImpl(PathInitializer filename, Options&& options) {
+void FdMMapReader<Src>::OpenImpl(PathInitializer filename,
+                                 const Options& options) {
   absl::Status status = src_.manager().Open(std::move(filename), options.mode(),
                                             OwnedFd::kDefaultPermissions);
   if (ABSL_PREDICT_FALSE(!status.ok())) {
@@ -479,14 +488,14 @@
     FailWithoutAnnotation(std::move(status));
     return;
   }
-  InitializePos(src_.get().get(), std::move(options));
+  InitializePos(src_.get().get(), options);
 }
 
 template <typename Src>
 template <typename DependentSrc,
           std::enable_if_t<FdSupportsOpenAt<DependentSrc>::value, int>>
 void FdMMapReader<Src>::OpenAtImpl(UnownedFd dir_fd, PathRef filename,
-                                   Options&& options) {
+                                   const Options& options) {
   absl::Status status =
       src_.manager().OpenAt(std::move(dir_fd), absl::string_view(filename),
                             options.mode(), OwnedFd::kDefaultPermissions);
@@ -495,7 +504,7 @@
     FailWithoutAnnotation(std::move(status));
     return;
   }
-  InitializePos(src_.get().get(), std::move(options));
+  InitializePos(src_.get().get(), options);
 }
 
 template <typename Src>
diff --git a/riegeli/bytes/fd_reader.cc b/riegeli/bytes/fd_reader.cc
index 8b5ad5a..bcb3e0a 100644
--- a/riegeli/bytes/fd_reader.cc
+++ b/riegeli/bytes/fd_reader.cc
@@ -160,18 +160,18 @@
 
 #endif
 
-void FdReaderBase::Initialize(int src, Options&& options) {
+void FdReaderBase::Initialize(int src, const Options& options) {
   RIEGELI_ASSERT_GE(src, 0)
       << "Failed precondition of FdReader: negative file descriptor";
-  InitializePos(src, std::move(options)
+  InitializePos(src, options
 #ifdef _WIN32
-                         ,
+                ,
                 /*mode_was_passed_to_open=*/false
 #endif
   );
 }
 
-void FdReaderBase::InitializePos(int src, Options&& options
+void FdReaderBase::InitializePos(int src, const Options& options
 #ifdef _WIN32
                                  ,
                                  bool mode_was_passed_to_open
@@ -200,7 +200,10 @@
     }
     original_mode_ = original_mode;
   }
-  if (options.assumed_pos() == std::nullopt) {
+#endif  // _WIN32
+  std::optional<Position> assumed_pos = options.assumed_pos();
+#ifdef _WIN32
+  if (assumed_pos == std::nullopt) {
     if (text_mode == 0) {
       // There is no `_getmode()`, but `_setmode()` returns the previous mode.
       text_mode = _setmode(src, _O_BINARY);
@@ -219,11 +222,11 @@
             "FdReaderBase::Options::independent_pos() requires binary mode"));
         return;
       }
-      options.set_assumed_pos(0);
+      assumed_pos = 0;
     }
   }
 #endif  // _WIN32
-  if (options.assumed_pos() != std::nullopt) {
+  if (assumed_pos != std::nullopt) {
     if (ABSL_PREDICT_FALSE(options.independent_pos() != std::nullopt)) {
       Fail(absl::InvalidArgumentError(
           "FdReaderBase::Options::assumed_pos() and independent_pos() "
@@ -231,12 +234,12 @@
       return;
     }
     if (ABSL_PREDICT_FALSE(
-            *options.assumed_pos() >
+            *assumed_pos >
             Position{std::numeric_limits<fd_internal::Offset>::max()})) {
       FailOverflow();
       return;
     }
-    set_limit_pos(*options.assumed_pos());
+    set_limit_pos(*assumed_pos);
     // `supports_random_access_` is left as `false`.
     random_access_status_ = Global([] {
       return absl::UnimplementedError(
diff --git a/riegeli/bytes/fd_reader.h b/riegeli/bytes/fd_reader.h
index 24214bc..a5c79d0 100644
--- a/riegeli/bytes/fd_reader.h
+++ b/riegeli/bytes/fd_reader.h
@@ -53,6 +53,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // If `FdReader` opens a fd with a filename, `mode()` is the second argument
     // of `open()` (on Windows: `_open()`) and specifies the open mode and
     // flags, typically `O_RDONLY` (on Windows: `_O_RDONLY | _O_BINARY`).
@@ -243,8 +246,8 @@
 
   void Reset(Closed);
   void Reset(BufferOptions buffer_options, bool growing_source);
-  void Initialize(int src, Options&& options);
-  void InitializePos(int src, Options&& options
+  void Initialize(int src, const Options& options);
+  void InitializePos(int src, const Options& options
 #ifdef _WIN32
                      ,
                      bool mode_was_passed_to_open
@@ -337,14 +340,14 @@
   explicit FdReader(Closed) noexcept : FdReaderBase(kClosed) {}
 
   // Will read from the fd provided by `src`.
-  explicit FdReader(Initializer<Src> src, Options options = Options());
+  explicit FdReader(Initializer<Src> src, const Options& options = Options());
 
   // Will read from `src`.
   template <
       typename DependentSrc = Src,
       std::enable_if_t<std::is_constructible_v<DependentSrc, int>, int> = 0>
   explicit FdReader(int src ABSL_ATTRIBUTE_LIFETIME_BOUND,
-                    Options options = Options());
+                    const Options& options = Options());
 
   // Opens a file for reading.
   //
@@ -356,7 +359,8 @@
                 std::conjunction_v<FdSupportsOpen<DependentSrc>,
                                    std::is_default_constructible<DependentSrc>>,
                 int> = 0>
-  explicit FdReader(PathInitializer filename, Options options = Options());
+  explicit FdReader(PathInitializer filename,
+                    const Options& options = Options());
 
   // Opens a file for reading, with the filename interpreted relatively to the
   // directory specified by an existing fd.
@@ -370,7 +374,7 @@
                                    std::is_default_constructible<DependentSrc>>,
                 int> = 0>
   explicit FdReader(UnownedFd dir_fd, PathRef filename,
-                    Options options = Options());
+                    const Options& options = Options());
 
   FdReader(FdReader&& that) = default;
   FdReader& operator=(FdReader&& that) = default;
@@ -379,24 +383,25 @@
   // constructing a temporary `FdReader` and moving from it.
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Closed);
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Initializer<Src> src,
-                                          Options options = Options());
+                                          const Options& options = Options());
   template <
       typename DependentSrc = Src,
       std::enable_if_t<std::is_constructible_v<DependentSrc, int>, int> = 0>
-  ABSL_ATTRIBUTE_REINITIALIZES void Reset(int src, Options options = Options());
+  ABSL_ATTRIBUTE_REINITIALIZES void Reset(int src,
+                                          const Options& options = Options());
   template <typename DependentSrc = Src,
             std::enable_if_t<std::conjunction_v<FdSupportsOpen<DependentSrc>,
                                                 SupportsReset<DependentSrc>>,
                              int> = 0>
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(PathInitializer filename,
-                                          Options options = Options());
+                                          const Options& options = Options());
   template <typename DependentSrc = Src,
             std::enable_if_t<std::conjunction_v<FdSupportsOpenAt<DependentSrc>,
                                                 SupportsReset<DependentSrc>>,
                              int> = 0>
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(UnownedFd dir_fd,
                                           PathInitializer filename,
-                                          Options options = Options());
+                                          const Options& options = Options());
 
   // Returns the object providing and possibly owning the fd being read from.
   // Unchanged by `Close()`.
@@ -422,10 +427,10 @@
  private:
   template <typename DependentSrc = Src,
             std::enable_if_t<FdSupportsOpen<DependentSrc>::value, int> = 0>
-  void OpenImpl(PathInitializer filename, Options&& options);
+  void OpenImpl(PathInitializer filename, const Options& options);
   template <typename DependentSrc = Src,
             std::enable_if_t<FdSupportsOpenAt<DependentSrc>::value, int> = 0>
-  void OpenAtImpl(UnownedFd dir_fd, PathRef filename, Options&& options);
+  void OpenAtImpl(UnownedFd dir_fd, PathRef filename, const Options& options);
 
   // The object providing and possibly owning the fd being read from.
   Dependency<FdHandle, Src> src_;
@@ -433,15 +438,15 @@
 
 explicit FdReader(Closed) -> FdReader<DeleteCtad<Closed>>;
 template <typename Src>
-explicit FdReader(Src&& src,
-                  FdReaderBase::Options options = FdReaderBase::Options())
+explicit FdReader(
+    Src&& src, const FdReaderBase::Options& options = FdReaderBase::Options())
     -> FdReader<std::conditional_t<
         std::disjunction_v<std::is_convertible<Src&&, int>,
                            std::is_convertible<Src&&, PathInitializer>>,
         OwnedFd, TargetT<Src>>>;
 explicit FdReader(UnownedFd dir_fd, PathRef filename,
-                  FdReaderBase::Options options = FdReaderBase::Options())
-    -> FdReader<OwnedFd>;
+                  const FdReaderBase::Options& options =
+                      FdReaderBase::Options()) -> FdReader<OwnedFd>;
 
 // Implementation details follow.
 
@@ -499,18 +504,18 @@
 }
 
 template <typename Src>
-inline FdReader<Src>::FdReader(Initializer<Src> src, Options options)
+inline FdReader<Src>::FdReader(Initializer<Src> src, const Options& options)
     : FdReaderBase(options.buffer_options(), options.growing_source()),
       src_(std::move(src)) {
-  Initialize(src_.get().get(), std::move(options));
+  Initialize(src_.get().get(), options);
 }
 
 template <typename Src>
 template <typename DependentSrc,
           std::enable_if_t<std::is_constructible_v<DependentSrc, int>, int>>
 inline FdReader<Src>::FdReader(int src ABSL_ATTRIBUTE_LIFETIME_BOUND,
-                               Options options)
-    : FdReader(riegeli::Maker(src), std::move(options)) {}
+                               const Options& options)
+    : FdReader(riegeli::Maker(src), options) {}
 
 template <typename Src>
 template <typename DependentSrc,
@@ -518,10 +523,10 @@
               std::conjunction_v<FdSupportsOpen<DependentSrc>,
                                  std::is_default_constructible<DependentSrc>>,
               int>>
-inline FdReader<Src>::FdReader(PathInitializer filename, Options options)
+inline FdReader<Src>::FdReader(PathInitializer filename, const Options& options)
     : FdReaderBase(options.buffer_options(), options.growing_source()),
       src_(riegeli::Maker()) {
-  OpenImpl(std::move(filename), std::move(options));
+  OpenImpl(std::move(filename), options);
 }
 
 template <typename Src>
@@ -531,10 +536,10 @@
                                  std::is_default_constructible<DependentSrc>>,
               int>>
 inline FdReader<Src>::FdReader(UnownedFd dir_fd, PathRef filename,
-                               Options options)
+                               const Options& options)
     : FdReaderBase(options.buffer_options(), options.growing_source()),
       src_(riegeli::Maker()) {
-  OpenAtImpl(std::move(dir_fd), filename, std::move(options));
+  OpenAtImpl(std::move(dir_fd), filename, options);
 }
 
 template <typename Src>
@@ -544,17 +549,17 @@
 }
 
 template <typename Src>
-inline void FdReader<Src>::Reset(Initializer<Src> src, Options options) {
+inline void FdReader<Src>::Reset(Initializer<Src> src, const Options& options) {
   FdReaderBase::Reset(options.buffer_options(), options.growing_source());
   src_.Reset(std::move(src));
-  Initialize(src_.get().get(), std::move(options));
+  Initialize(src_.get().get(), options);
 }
 
 template <typename Src>
 template <typename DependentSrc,
           std::enable_if_t<std::is_constructible_v<DependentSrc, int>, int>>
-inline void FdReader<Src>::Reset(int src, Options options) {
-  Reset(riegeli::Maker(src), std::move(options));
+inline void FdReader<Src>::Reset(int src, const Options& options) {
+  Reset(riegeli::Maker(src), options);
 }
 
 template <typename Src>
@@ -562,12 +567,13 @@
           std::enable_if_t<std::conjunction_v<FdSupportsOpen<DependentSrc>,
                                               SupportsReset<DependentSrc>>,
                            int>>
-inline void FdReader<Src>::Reset(PathInitializer filename, Options options) {
+inline void FdReader<Src>::Reset(PathInitializer filename,
+                                 const Options& options) {
   // In case `filename` is owned by `src_` and gets invalidated.
   std::string filename_copy = std::move(filename);
   riegeli::Reset(src_.manager());
   FdReaderBase::Reset(options.buffer_options(), options.growing_source());
-  OpenImpl(std::move(filename_copy), std::move(options));
+  OpenImpl(std::move(filename_copy), options);
 }
 
 template <typename Src>
@@ -576,18 +582,18 @@
                                               SupportsReset<DependentSrc>>,
                            int>>
 inline void FdReader<Src>::Reset(UnownedFd dir_fd, PathInitializer filename,
-                                 Options options) {
+                                 const Options& options) {
   // In case `filename` is owned by `src_` and gets invalidated.
   std::string filename_copy = std::move(filename);
   riegeli::Reset(src_.manager());
   FdReaderBase::Reset(options.buffer_options(), options.growing_source());
-  OpenAtImpl(dir_fd, filename_copy, std::move(options));
+  OpenAtImpl(dir_fd, filename_copy, options);
 }
 
 template <typename Src>
 template <typename DependentSrc,
           std::enable_if_t<FdSupportsOpen<DependentSrc>::value, int>>
-void FdReader<Src>::OpenImpl(PathInitializer filename, Options&& options) {
+void FdReader<Src>::OpenImpl(PathInitializer filename, const Options& options) {
   absl::Status status = src_.manager().Open(std::move(filename), options.mode(),
                                             OwnedFd::kDefaultPermissions);
   if (ABSL_PREDICT_FALSE(!status.ok())) {
@@ -595,9 +601,9 @@
     FailWithoutAnnotation(std::move(status));
     return;
   }
-  InitializePos(src_.get().get(), std::move(options)
+  InitializePos(src_.get().get(), options
 #ifdef _WIN32
-                                      ,
+                ,
                 /*mode_was_passed_to_open=*/true
 #endif
   );
@@ -607,7 +613,7 @@
 template <typename DependentSrc,
           std::enable_if_t<FdSupportsOpenAt<DependentSrc>::value, int>>
 void FdReader<Src>::OpenAtImpl(UnownedFd dir_fd, PathRef filename,
-                               Options&& options) {
+                               const Options& options) {
   absl::Status status =
       src_.manager().OpenAt(std::move(dir_fd), absl::string_view(filename),
                             options.mode(), OwnedFd::kDefaultPermissions);
@@ -616,9 +622,9 @@
     FailWithoutAnnotation(std::move(status));
     return;
   }
-  InitializePos(src_.get().get(), std::move(options)
+  InitializePos(src_.get().get(), options
 #ifdef _WIN32
-                                      ,
+                ,
                 /*mode_was_passed_to_open=*/true
 #endif
   );
diff --git a/riegeli/bytes/fd_writer.cc b/riegeli/bytes/fd_writer.cc
index 53ee874..af2272d 100644
--- a/riegeli/bytes/fd_writer.cc
+++ b/riegeli/bytes/fd_writer.cc
@@ -58,10 +58,10 @@
 #include "riegeli/base/arithmetic.h"
 #include "riegeli/base/assert.h"
 #include "riegeli/base/buffering.h"
+#include "riegeli/base/byte_fill.h"
 #ifdef _WIN32
 #include "riegeli/base/errno_mapping.h"
 #endif
-#include "riegeli/base/byte_fill.h"
 #include "riegeli/base/global.h"
 #include "riegeli/base/status.h"
 #include "riegeli/base/type_id.h"
@@ -77,13 +77,13 @@
 
 TypeId FdWriterBase::GetTypeId() const { return TypeId::For<FdWriterBase>(); }
 
-void FdWriterBase::Initialize(int dest, Options&& options) {
+void FdWriterBase::Initialize(int dest, const Options& options) {
   RIEGELI_ASSERT_GE(dest, 0)
       << "Failed precondition of FdWriter: negative file descriptor";
-  InitializePos(dest, std::move(options), /*mode_was_passed_to_open=*/false);
+  InitializePos(dest, options, /*mode_was_passed_to_open=*/false);
 }
 
-void FdWriterBase::InitializePos(int dest, Options&& options,
+void FdWriterBase::InitializePos(int dest, const Options& options,
                                  bool mode_was_passed_to_open) {
   RIEGELI_ASSERT(!has_independent_pos_)
       << "Failed precondition of FdWriterBase::InitializePos(): "
@@ -100,29 +100,31 @@
   RIEGELI_ASSERT_OK(read_mode_status_)
       << "Failed precondition of FdWriterBase::InitializePos(): "
          "read_mode_status_ not reset";
+#ifdef _WIN32
+  RIEGELI_ASSERT_EQ(original_mode_, std::nullopt)
+      << "Failed precondition of FdWriterBase::InitializePos(): "
+         "original_mode_ not reset";
+#endif  // _WIN32
+  int mode = options.mode();
 #ifndef _WIN32
   if (!mode_was_passed_to_open) {
-    const int mode = fcntl(dest, F_GETFL);
+    mode = fcntl(dest, F_GETFL);
     if (ABSL_PREDICT_FALSE(mode < 0)) {
       FailOperation("fcntl()");
       return;
     }
-    options.set_mode(mode);
   }
-  if ((options.mode() & O_ACCMODE) != O_RDWR) {
+  if ((mode & O_ACCMODE) != O_RDWR) {
     supports_read_mode_ = LazyBoolState::kFalse;
     read_mode_status_ = Global([] {
       return absl::UnimplementedError("Mode does not include O_RDWR");
     });
   }
 #else   // _WIN32
-  RIEGELI_ASSERT_EQ(original_mode_, std::nullopt)
-      << "Failed precondition of FdWriterBase::InitializePos(): "
-         "original_mode_ not reset";
-  int text_mode = options.mode() &
-                  (_O_BINARY | _O_TEXT | _O_WTEXT | _O_U16TEXT | _O_U8TEXT);
+  int text_mode =
+      mode & (_O_BINARY | _O_TEXT | _O_WTEXT | _O_U16TEXT | _O_U8TEXT);
   if (mode_was_passed_to_open) {
-    if ((options.mode() & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDWR) {
+    if ((mode & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDWR) {
       supports_read_mode_ = LazyBoolState::kFalse;
       read_mode_status_ = Global([] {
         return absl::UnimplementedError("Mode does not include _O_RDWR");
@@ -136,7 +138,10 @@
     }
     original_mode_ = original_mode;
   }
-  if (options.assumed_pos() == std::nullopt) {
+#endif  // _WIN32
+  std::optional<Position> assumed_pos = options.assumed_pos();
+#ifdef _WIN32
+  if (assumed_pos == std::nullopt) {
     if (text_mode == 0) {
       // There is no `_getmode()`, but `_setmode()` returns the previous mode.
       text_mode = _setmode(dest, _O_BINARY);
@@ -155,11 +160,11 @@
             "FdWriterBase::Options::independent_pos() requires binary mode"));
         return;
       }
-      options.set_assumed_pos(0);
+      assumed_pos = 0;
     }
   }
 #endif  // _WIN32
-  if (options.assumed_pos() != std::nullopt) {
+  if (assumed_pos != std::nullopt) {
     if (ABSL_PREDICT_FALSE(options.independent_pos() != std::nullopt)) {
       Fail(absl::InvalidArgumentError(
           "FdWriterBase::Options::assumed_pos() and independent_pos() "
@@ -167,12 +172,12 @@
       return;
     }
     if (ABSL_PREDICT_FALSE(
-            *options.assumed_pos() >
+            *assumed_pos >
             Position{std::numeric_limits<fd_internal::Offset>::max()})) {
       FailOverflow();
       return;
     }
-    set_start_pos(*options.assumed_pos());
+    set_start_pos(*assumed_pos);
     supports_random_access_ = LazyBoolState::kFalse;
     supports_read_mode_ = LazyBoolState::kFalse;
     random_access_status_ = Global([] {
@@ -181,7 +186,7 @@
     });
     read_mode_status_.Update(random_access_status_);
   } else if (options.independent_pos() != std::nullopt) {
-    if (ABSL_PREDICT_FALSE((options.mode() & O_APPEND) != 0)) {
+    if (ABSL_PREDICT_FALSE((mode & O_APPEND) != 0)) {
       Fail(
           absl::InvalidArgumentError("FdWriterBase::Options::independent_pos() "
                                      "is incompatible with append mode"));
@@ -205,7 +210,7 @@
     }
   } else {
     const fd_internal::Offset file_pos = fd_internal::LSeek(
-        dest, 0, (options.mode() & O_APPEND) != 0 ? SEEK_END : SEEK_CUR);
+        dest, 0, (mode & O_APPEND) != 0 ? SEEK_END : SEEK_CUR);
     if (file_pos < 0) {
       // Random access is not supported. Assume 0 as the initial position.
       supports_random_access_ = LazyBoolState::kFalse;
@@ -216,7 +221,7 @@
       return;
     }
     set_start_pos(IntCast<Position>(file_pos));
-    if ((options.mode() & O_APPEND) != 0) {
+    if ((mode & O_APPEND) != 0) {
       // `fd_internal::LSeek(SEEK_END)` succeeded.
       supports_random_access_ = LazyBoolState::kFalse;
       if (
diff --git a/riegeli/bytes/fd_writer.h b/riegeli/bytes/fd_writer.h
index decc4f6..7725cf2 100644
--- a/riegeli/bytes/fd_writer.h
+++ b/riegeli/bytes/fd_writer.h
@@ -58,6 +58,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // If `FdWriter` opens a fd with a filename, `mode()` is the second argument
     // of `open()` (on Windows: `_open()`) and specifies the open mode and
     // flags, typically one of:
@@ -381,8 +384,9 @@
 
   void Reset(Closed);
   void Reset(BufferOptions buffer_options);
-  void Initialize(int dest, Options&& options);
-  void InitializePos(int dest, Options&& options, bool mode_was_passed_to_open);
+  void Initialize(int dest, const Options& options);
+  void InitializePos(int dest, const Options& options,
+                     bool mode_was_passed_to_open);
   ABSL_ATTRIBUTE_COLD bool FailOperation(absl::string_view operation);
 #ifdef _WIN32
   ABSL_ATTRIBUTE_COLD bool FailWindowsOperation(absl::string_view operation);
@@ -511,14 +515,14 @@
   explicit FdWriter(Closed) noexcept : FdWriterBase(kClosed) {}
 
   // Will write to the fd provided by `dest`.
-  explicit FdWriter(Initializer<Dest> dest, Options options = Options());
+  explicit FdWriter(Initializer<Dest> dest, const Options& options = Options());
 
   // Will write to `dest`.
   template <
       typename DependentDest = Dest,
       std::enable_if_t<std::is_constructible_v<DependentDest, int>, int> = 0>
   explicit FdWriter(int dest ABSL_ATTRIBUTE_LIFETIME_BOUND,
-                    Options options = Options());
+                    const Options& options = Options());
 
   // Opens a file for writing.
   //
@@ -530,7 +534,8 @@
                                  FdSupportsOpen<DependentDest>,
                                  std::is_default_constructible<DependentDest>>,
                              int> = 0>
-  explicit FdWriter(PathInitializer filename, Options options = Options());
+  explicit FdWriter(PathInitializer filename,
+                    const Options& options = Options());
 
   // Opens a file for writing, with the filename interpreted relatively to the
   // directory specified by an existing fd.
@@ -544,7 +549,7 @@
                                  std::is_default_constructible<DependentDest>>,
                              int> = 0>
   explicit FdWriter(UnownedFd dir_fd, PathRef filename,
-                    Options options = Options());
+                    const Options& options = Options());
 
   FdWriter(FdWriter&& that) = default;
   FdWriter& operator=(FdWriter&& that) = default;
@@ -553,25 +558,25 @@
   // constructing a temporary `FdWriter` and moving from it.
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Closed);
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Initializer<Dest> dest,
-                                          Options options = Options());
+                                          const Options& options = Options());
   template <
       typename DependentDest = Dest,
       std::enable_if_t<std::is_constructible_v<DependentDest, int>, int> = 0>
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(int dest,
-                                          Options options = Options());
+                                          const Options& options = Options());
   template <typename DependentDest = Dest,
             std::enable_if_t<std::conjunction_v<FdSupportsOpen<DependentDest>,
                                                 SupportsReset<DependentDest>>,
                              int> = 0>
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(PathInitializer filename,
-                                          Options options = Options());
+                                          const Options& options = Options());
   template <typename DependentDest = Dest,
             std::enable_if_t<std::conjunction_v<FdSupportsOpenAt<DependentDest>,
                                                 SupportsReset<DependentDest>>,
                              int> = 0>
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(UnownedFd dir_fd,
                                           PathInitializer filename,
-                                          Options options = Options());
+                                          const Options& options = Options());
 
   // Returns the object providing and possibly owning the fd being written to.
   // Unchanged by `Close()`.
@@ -597,10 +602,10 @@
  private:
   template <typename DependentDest = Dest,
             std::enable_if_t<FdSupportsOpen<DependentDest>::value, int> = 0>
-  void OpenImpl(PathInitializer filename, Options&& options);
+  void OpenImpl(PathInitializer filename, const Options& options);
   template <typename DependentDest = Dest,
             std::enable_if_t<FdSupportsOpenAt<DependentDest>::value, int> = 0>
-  void OpenAtImpl(UnownedFd dir_fd, PathRef filename, Options&& options);
+  void OpenAtImpl(UnownedFd dir_fd, PathRef filename, const Options& options);
 
   // The object providing and possibly owning the fd being written to.
   Dependency<FdHandle, Dest> dest_;
@@ -608,15 +613,15 @@
 
 explicit FdWriter(Closed) -> FdWriter<DeleteCtad<Closed>>;
 template <typename Dest>
-explicit FdWriter(Dest&& dest,
-                  FdWriterBase::Options options = FdWriterBase::Options())
+explicit FdWriter(
+    Dest&& dest, const FdWriterBase::Options& options = FdWriterBase::Options())
     -> FdWriter<std::conditional_t<
         std::disjunction_v<std::is_convertible<Dest&&, int>,
                            std::is_convertible<Dest&&, PathInitializer>>,
         OwnedFd, TargetT<Dest>>>;
 explicit FdWriter(UnownedFd dir_fd, PathRef filename,
-                  FdWriterBase::Options options = FdWriterBase::Options())
-    -> FdWriter<OwnedFd>;
+                  const FdWriterBase::Options& options =
+                      FdWriterBase::Options()) -> FdWriter<OwnedFd>;
 
 // Implementation details follow.
 
@@ -685,17 +690,17 @@
 }
 
 template <typename Dest>
-inline FdWriter<Dest>::FdWriter(Initializer<Dest> dest, Options options)
+inline FdWriter<Dest>::FdWriter(Initializer<Dest> dest, const Options& options)
     : FdWriterBase(options.buffer_options()), dest_(std::move(dest)) {
-  Initialize(dest_.get().get(), std::move(options));
+  Initialize(dest_.get().get(), options);
 }
 
 template <typename Dest>
 template <typename DependentDest,
           std::enable_if_t<std::is_constructible_v<DependentDest, int>, int>>
 inline FdWriter<Dest>::FdWriter(int dest ABSL_ATTRIBUTE_LIFETIME_BOUND,
-                                Options options)
-    : FdWriter(riegeli::Maker(dest), std::move(options)) {}
+                                const Options& options)
+    : FdWriter(riegeli::Maker(dest), options) {}
 
 template <typename Dest>
 template <typename DependentDest,
@@ -703,9 +708,10 @@
               std::conjunction_v<FdSupportsOpen<DependentDest>,
                                  std::is_default_constructible<DependentDest>>,
               int>>
-inline FdWriter<Dest>::FdWriter(PathInitializer filename, Options options)
+inline FdWriter<Dest>::FdWriter(PathInitializer filename,
+                                const Options& options)
     : FdWriterBase(options.buffer_options()), dest_(riegeli::Maker()) {
-  OpenImpl(std::move(filename), std::move(options));
+  OpenImpl(std::move(filename), options);
 }
 
 template <typename Dest>
@@ -715,9 +721,9 @@
                                  std::is_default_constructible<DependentDest>>,
               int>>
 inline FdWriter<Dest>::FdWriter(UnownedFd dir_fd, PathRef filename,
-                                Options options)
+                                const Options& options)
     : FdWriterBase(options.buffer_options()), dest_(riegeli::Maker()) {
-  OpenAtImpl(std::move(dir_fd), filename, std::move(options));
+  OpenAtImpl(std::move(dir_fd), filename, options);
 }
 
 template <typename Dest>
@@ -727,17 +733,18 @@
 }
 
 template <typename Dest>
-inline void FdWriter<Dest>::Reset(Initializer<Dest> dest, Options options) {
+inline void FdWriter<Dest>::Reset(Initializer<Dest> dest,
+                                  const Options& options) {
   FdWriterBase::Reset(options.buffer_options());
   dest_.Reset(std::move(dest));
-  Initialize(dest_.get().get(), std::move(options));
+  Initialize(dest_.get().get(), options);
 }
 
 template <typename Dest>
 template <typename DependentDest,
           std::enable_if_t<std::is_constructible_v<DependentDest, int>, int>>
-inline void FdWriter<Dest>::Reset(int dest, Options options) {
-  Reset(riegeli::Maker(dest), std::move(options));
+inline void FdWriter<Dest>::Reset(int dest, const Options& options) {
+  Reset(riegeli::Maker(dest), options);
 }
 
 template <typename Dest>
@@ -745,12 +752,13 @@
           std::enable_if_t<std::conjunction_v<FdSupportsOpen<DependentDest>,
                                               SupportsReset<DependentDest>>,
                            int>>
-inline void FdWriter<Dest>::Reset(PathInitializer filename, Options options) {
+inline void FdWriter<Dest>::Reset(PathInitializer filename,
+                                  const Options& options) {
   // In case `filename` is owned by `dest_` and gets invalidated.
   std::string filename_copy = std::move(filename);
   riegeli::Reset(dest_.manager());
   FdWriterBase::Reset(options.buffer_options());
-  OpenImpl(std::move(filename_copy), std::move(options));
+  OpenImpl(std::move(filename_copy), options);
 }
 
 template <typename Dest>
@@ -759,18 +767,19 @@
                                               SupportsReset<DependentDest>>,
                            int>>
 inline void FdWriter<Dest>::Reset(UnownedFd dir_fd, PathInitializer filename,
-                                  Options options) {
+                                  const Options& options) {
   // In case `filename` is owned by `dest_` and gets invalidated.
   std::string filename_copy = std::move(filename);
   riegeli::Reset(dest_.manager());
   FdWriterBase::Reset(options.buffer_options());
-  OpenAtImpl(dir_fd, filename_copy, std::move(options));
+  OpenAtImpl(dir_fd, filename_copy, options);
 }
 
 template <typename Dest>
 template <typename DependentDest,
           std::enable_if_t<FdSupportsOpen<DependentDest>::value, int>>
-void FdWriter<Dest>::OpenImpl(PathInitializer filename, Options&& options) {
+void FdWriter<Dest>::OpenImpl(PathInitializer filename,
+                              const Options& options) {
   absl::Status status = dest_.manager().Open(
       std::move(filename), options.mode(), options.permissions());
   if (ABSL_PREDICT_FALSE(!status.ok())) {
@@ -778,7 +787,7 @@
     FailWithoutAnnotation(std::move(status));
     return;
   }
-  InitializePos(dest_.get().get(), std::move(options),
+  InitializePos(dest_.get().get(), options,
                 /*mode_was_passed_to_open=*/true);
 }
 
@@ -786,7 +795,7 @@
 template <typename DependentDest,
           std::enable_if_t<FdSupportsOpenAt<DependentDest>::value, int>>
 void FdWriter<Dest>::OpenAtImpl(UnownedFd dir_fd, PathRef filename,
-                                Options&& options) {
+                                const Options& options) {
   absl::Status status =
       dest_.manager().OpenAt(std::move(dir_fd), absl::string_view(filename),
                              options.mode(), options.permissions());
@@ -795,7 +804,7 @@
     FailWithoutAnnotation(std::move(status));
     return;
   }
-  InitializePos(dest_.get().get(), std::move(options),
+  InitializePos(dest_.get().get(), options,
                 /*mode_was_passed_to_open=*/true);
 }
 
diff --git a/riegeli/bytes/istream_reader.h b/riegeli/bytes/istream_reader.h
index fa83672..6c6e03b 100644
--- a/riegeli/bytes/istream_reader.h
+++ b/riegeli/bytes/istream_reader.h
@@ -43,6 +43,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // If `std::nullopt`, the current position reported by `pos()` corresponds
     // to the current stream position if possible, otherwise 0 is assumed as the
     // initial position. Random access is supported if the stream supports
diff --git a/riegeli/bytes/limiting_backward_writer.cc b/riegeli/bytes/limiting_backward_writer.cc
index 20a33e7..562f3e8 100644
--- a/riegeli/bytes/limiting_backward_writer.cc
+++ b/riegeli/bytes/limiting_backward_writer.cc
@@ -37,8 +37,7 @@
 namespace riegeli {
 
 void LimitingBackwardWriterBase::Initialize(BackwardWriter* dest,
-                                            const Options& options,
-                                            bool is_owning) {
+                                            Options options, bool is_owning) {
   RIEGELI_ASSERT_NE(dest, nullptr)
       << "Failed precondition of LimitingBackwardWriter: "
          "null BackwardWriter pointer";
diff --git a/riegeli/bytes/limiting_backward_writer.h b/riegeli/bytes/limiting_backward_writer.h
index 42ab26e..18acf31 100644
--- a/riegeli/bytes/limiting_backward_writer.h
+++ b/riegeli/bytes/limiting_backward_writer.h
@@ -46,6 +46,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // The limit expressed as an absolute position.
     //
     // `std::nullopt` means no limit, unless `max_length()` is set.
@@ -161,7 +164,7 @@
 
   void Reset(Closed);
   void Reset(bool exact);
-  void Initialize(BackwardWriter* dest, const Options& options, bool is_owning);
+  void Initialize(BackwardWriter* dest, Options options, bool is_owning);
   bool exact() const { return exact_; }
 
   // Sets cursor of `dest` to cursor of `*this`. Fails `*this` if the limit is
diff --git a/riegeli/bytes/limiting_reader.cc b/riegeli/bytes/limiting_reader.cc
index c4f9d06..dd1f421 100644
--- a/riegeli/bytes/limiting_reader.cc
+++ b/riegeli/bytes/limiting_reader.cc
@@ -36,7 +36,7 @@
 
 namespace riegeli {
 
-void LimitingReaderBase::Initialize(Reader* src, const Options& options) {
+void LimitingReaderBase::Initialize(Reader* src, Options options) {
   RIEGELI_ASSERT_NE(src, nullptr)
       << "Failed precondition of LimitingReader: null Reader pointer";
   set_buffer(src->start(), src->start_to_limit(), src->start_to_cursor());
diff --git a/riegeli/bytes/limiting_reader.h b/riegeli/bytes/limiting_reader.h
index 30b1981..951b3fd 100644
--- a/riegeli/bytes/limiting_reader.h
+++ b/riegeli/bytes/limiting_reader.h
@@ -50,6 +50,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // The limit expressed as an absolute position.
     //
     // `std::nullopt` means no limit, unless `max_length()` is set.
@@ -224,7 +227,7 @@
 
   void Reset(Closed);
   void Reset(bool exact, bool fail_if_longer);
-  void Initialize(Reader* src, const Options& options);
+  void Initialize(Reader* src, Options options);
 
   // Sets cursor of `src` to cursor of `*this`.
   void SyncBuffer(Reader& src);
diff --git a/riegeli/bytes/limiting_writer.cc b/riegeli/bytes/limiting_writer.cc
index 117e9f3..467259c 100644
--- a/riegeli/bytes/limiting_writer.cc
+++ b/riegeli/bytes/limiting_writer.cc
@@ -37,7 +37,7 @@
 
 namespace riegeli {
 
-void LimitingWriterBase::Initialize(Writer* dest, const Options& options,
+void LimitingWriterBase::Initialize(Writer* dest, Options options,
                                     bool is_owning) {
   RIEGELI_ASSERT_NE(dest, nullptr)
       << "Failed precondition of LimitingWriter: null Writer pointer";
diff --git a/riegeli/bytes/limiting_writer.h b/riegeli/bytes/limiting_writer.h
index 2a4f65d..3151c54 100644
--- a/riegeli/bytes/limiting_writer.h
+++ b/riegeli/bytes/limiting_writer.h
@@ -48,6 +48,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // The limit expressed as an absolute position.
     //
     // `std::nullopt` means no limit, unless `max_length()` is set.
@@ -163,7 +166,7 @@
 
   void Reset(Closed);
   void Reset(bool exact);
-  void Initialize(Writer* dest, const Options& options, bool is_owning);
+  void Initialize(Writer* dest, Options options, bool is_owning);
   bool exact() const { return exact_; }
 
   // Sets cursor of `dest` to cursor of `*this`. Fails `*this` if the limit is
diff --git a/riegeli/bytes/null_backward_writer.h b/riegeli/bytes/null_backward_writer.h
index df678bb..b044fd8 100644
--- a/riegeli/bytes/null_backward_writer.h
+++ b/riegeli/bytes/null_backward_writer.h
@@ -44,6 +44,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // `NullBackwardWriter` has a smaller default buffer size (512) so that
     // writing larger values is skipped altogether.
     static constexpr size_t kDefaultMinBufferSize = kMaxBytesToCopy + 1;
diff --git a/riegeli/bytes/null_writer.h b/riegeli/bytes/null_writer.h
index f51914f..86fc12d 100644
--- a/riegeli/bytes/null_writer.h
+++ b/riegeli/bytes/null_writer.h
@@ -24,7 +24,6 @@
 #include "absl/strings/cord.h"
 #include "absl/strings/string_view.h"
 #include "riegeli/base/buffer.h"
-#include "riegeli/base/buffering.h"
 #include "riegeli/base/byte_fill.h"
 #include "riegeli/base/chain.h"
 #include "riegeli/base/external_ref.h"
@@ -44,6 +43,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // `NullWriter` has a smaller default buffer size (1024) so that writing
     // larger values is skipped altogether.
     static constexpr size_t kDefaultMinBufferSize = 1 << 10;
diff --git a/riegeli/bytes/ostream_writer.h b/riegeli/bytes/ostream_writer.h
index 56acbf2..d736df9 100644
--- a/riegeli/bytes/ostream_writer.h
+++ b/riegeli/bytes/ostream_writer.h
@@ -50,6 +50,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // If `std::nullopt`, the current position reported by `pos()` corresponds
     // to the current stream position if possible, otherwise 0 is assumed as the
     // initial position. Random access is supported if the stream supports
diff --git a/riegeli/bytes/position_shifting_backward_writer.h b/riegeli/bytes/position_shifting_backward_writer.h
index c2ef749..d757433 100644
--- a/riegeli/bytes/position_shifting_backward_writer.h
+++ b/riegeli/bytes/position_shifting_backward_writer.h
@@ -47,6 +47,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // The base position of the new `BackwardWriter`.
     //
     // Default: 0.
diff --git a/riegeli/bytes/position_shifting_reader.h b/riegeli/bytes/position_shifting_reader.h
index ae541f9..7af997a 100644
--- a/riegeli/bytes/position_shifting_reader.h
+++ b/riegeli/bytes/position_shifting_reader.h
@@ -48,6 +48,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // The base position of the new `Reader`.
     //
     // Default: 0.
diff --git a/riegeli/bytes/position_shifting_writer.h b/riegeli/bytes/position_shifting_writer.h
index ed5dfda..254eb57 100644
--- a/riegeli/bytes/position_shifting_writer.h
+++ b/riegeli/bytes/position_shifting_writer.h
@@ -51,6 +51,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // The base position of the new `Writer`.
     //
     // Default: 0.
diff --git a/riegeli/bytes/prefix_limiting_backward_writer.h b/riegeli/bytes/prefix_limiting_backward_writer.h
index e48e748..732a6ca 100644
--- a/riegeli/bytes/prefix_limiting_backward_writer.h
+++ b/riegeli/bytes/prefix_limiting_backward_writer.h
@@ -50,6 +50,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // The base position of the original `BackwardWriter`. It must be at least
     // as large as the initial position.
     //
diff --git a/riegeli/bytes/prefix_limiting_reader.h b/riegeli/bytes/prefix_limiting_reader.h
index 14aa1b1..b881dc5 100644
--- a/riegeli/bytes/prefix_limiting_reader.h
+++ b/riegeli/bytes/prefix_limiting_reader.h
@@ -46,6 +46,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // The base position of the original `Reader`. It must be at least as large
     // as the initial position.
     //
diff --git a/riegeli/bytes/prefix_limiting_writer.h b/riegeli/bytes/prefix_limiting_writer.h
index 86f077e..b0895a0 100644
--- a/riegeli/bytes/prefix_limiting_writer.h
+++ b/riegeli/bytes/prefix_limiting_writer.h
@@ -50,6 +50,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // The base position of the original `Writer`. It must be at least as large
     // as the initial position.
     //
diff --git a/riegeli/bytes/reader_cfile.h b/riegeli/bytes/reader_cfile.h
index a7aaed6..eb47e62 100644
--- a/riegeli/bytes/reader_cfile.h
+++ b/riegeli/bytes/reader_cfile.h
@@ -42,6 +42,12 @@
  public:
   ReaderCFileOptions() noexcept {}
 
+  ReaderCFileOptions(const ReaderCFileOptions& that) = default;
+  ReaderCFileOptions& operator=(const ReaderCFileOptions& that) = default;
+
+  ReaderCFileOptions(ReaderCFileOptions&& that) = default;
+  ReaderCFileOptions& operator=(ReaderCFileOptions&& that) = default;
+
   // The filename assumed by the returned `OwnedCFile`.
   //
   // Default: "<unspecified>".
diff --git a/riegeli/bytes/reader_factory.h b/riegeli/bytes/reader_factory.h
index 06d16d4..1f4b6fd 100644
--- a/riegeli/bytes/reader_factory.h
+++ b/riegeli/bytes/reader_factory.h
@@ -36,7 +36,13 @@
 // Template parameter independent part of `ReaderFactory`.
 class ReaderFactoryBase : public Object {
  public:
-  class Options : public BufferOptionsBase<Options> {};
+  class Options : public BufferOptionsBase<Options> {
+   public:
+    Options() noexcept {}
+
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+  };
 
   // Returns the original `Reader`. Unchanged by `Close()`.
   virtual Reader* SrcReader() const ABSL_ATTRIBUTE_LIFETIME_BOUND = 0;
diff --git a/riegeli/bytes/reader_istream.h b/riegeli/bytes/reader_istream.h
index f87785f..a0d23e0 100644
--- a/riegeli/bytes/reader_istream.h
+++ b/riegeli/bytes/reader_istream.h
@@ -86,6 +86,9 @@
   class Options {
    public:
     Options() noexcept {}
+
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
   };
 
   // Returns the `Reader`. Unchanged by `close()`.
diff --git a/riegeli/bytes/resizable_writer.h b/riegeli/bytes/resizable_writer.h
index dd70714..3a55621 100644
--- a/riegeli/bytes/resizable_writer.h
+++ b/riegeli/bytes/resizable_writer.h
@@ -55,6 +55,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // If `false`, replaces existing contents of the destination, clearing it
     // first.
     //
@@ -539,7 +542,7 @@
             std::is_default_constructible<typename ResizableTraits::Resizable>>,
         int>>
 inline ResizableWriter<ResizableTraits, Dest>::ResizableWriter(Options options)
-    : ResizableWriter(riegeli::Maker(), std::move(options)) {}
+    : ResizableWriter(riegeli::Maker(), options) {}
 
 template <typename ResizableTraits, typename Dest>
 inline void ResizableWriter<ResizableTraits, Dest>::Reset(Closed) {
@@ -564,7 +567,7 @@
             std::is_default_constructible<typename ResizableTraits::Resizable>>,
         int>>
 inline void ResizableWriter<ResizableTraits, Dest>::Reset(Options options) {
-  Reset(riegeli::Maker(), std::move(options));
+  Reset(riegeli::Maker(), options);
 }
 
 template <typename ResizableTraits, typename Dest>
diff --git a/riegeli/bytes/std_io.cc b/riegeli/bytes/std_io.cc
index e6b3b01..be6eed9 100644
--- a/riegeli/bytes/std_io.cc
+++ b/riegeli/bytes/std_io.cc
@@ -36,13 +36,13 @@
 
 }  // namespace
 
-StdIn::StdIn(Options options) : FdReader(std_in_fd, std::move(options)) {
+StdIn::StdIn(const Options& options) : FdReader(std_in_fd, options) {
   SizedSharedBuffer& pending = StdInPending();
   if (!pending.empty()) RestoreBuffer(std::move(pending));
 }
 
-void StdIn::Reset(Options options) {
-  FdReader::Reset(std_in_fd, std::move(options));
+void StdIn::Reset(const Options& options) {
+  FdReader::Reset(std_in_fd, options);
   SizedSharedBuffer& pending = StdInPending();
   if (!pending.empty()) RestoreBuffer(std::move(pending));
 }
@@ -54,16 +54,16 @@
   FdReader::Done();
 }
 
-StdOut::StdOut(Options options) : FdWriter(std_out_fd, std::move(options)) {}
+StdOut::StdOut(const Options& options) : FdWriter(std_out_fd, options) {}
 
-void StdOut::Reset(Options options) {
-  FdWriter::Reset(std_out_fd, std::move(options));
+void StdOut::Reset(const Options& options) {
+  FdWriter::Reset(std_out_fd, options);
 }
 
-StdErr::StdErr(Options options) : FdWriter(std_err_fd, std::move(options)) {}
+StdErr::StdErr(const Options& options) : FdWriter(std_err_fd, options) {}
 
-void StdErr::Reset(Options options) {
-  FdWriter::Reset(std_err_fd, std::move(options));
+void StdErr::Reset(const Options& options) {
+  FdWriter::Reset(std_err_fd, options);
 }
 
 InjectedStdInFd::InjectedStdInFd(int fd)
diff --git a/riegeli/bytes/std_io.h b/riegeli/bytes/std_io.h
index 887f8f3..c364ed1 100644
--- a/riegeli/bytes/std_io.h
+++ b/riegeli/bytes/std_io.h
@@ -45,7 +45,7 @@
   explicit StdIn(Closed) noexcept : FdReader(kClosed) {}
 
   // Will read from standard input.
-  explicit StdIn(Options options = Options());
+  explicit StdIn(const Options& options = Options());
 
   StdIn(StdIn&& that) = default;
   StdIn& operator=(StdIn&& that) = default;
@@ -53,7 +53,7 @@
   // Makes `*this` equivalent to a newly constructed `StdIn`. This avoids
   // constructing a temporary `StdIn` and moving from it.
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Closed);
-  ABSL_ATTRIBUTE_REINITIALIZES void Reset(Options options = Options());
+  ABSL_ATTRIBUTE_REINITIALIZES void Reset(const Options& options = Options());
 
  protected:
   void Done() override;
@@ -91,7 +91,7 @@
   explicit StdOut(Closed) noexcept : FdWriter(kClosed) {}
 
   // Will write to standard output.
-  explicit StdOut(Options options = Options());
+  explicit StdOut(const Options& options = Options());
 
   StdOut(StdOut&& that) = default;
   StdOut& operator=(StdOut&& that) = default;
@@ -99,7 +99,7 @@
   // Makes `*this` equivalent to a newly constructed `StdOut`. This avoids
   // constructing a temporary `StdOut` and moving from it.
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Closed);
-  ABSL_ATTRIBUTE_REINITIALIZES void Reset(Options options = Options());
+  ABSL_ATTRIBUTE_REINITIALIZES void Reset(const Options& options = Options());
 };
 
 // A new `Writer` writing to standard error (by default to the same destination
@@ -130,7 +130,7 @@
   explicit StdErr(Closed) noexcept : FdWriter(kClosed) {}
 
   // Will write to standard error.
-  explicit StdErr(Options options = Options());
+  explicit StdErr(const Options& options = Options());
 
   StdErr(StdErr&& that) = default;
   StdErr& operator=(StdErr&& that) = default;
@@ -138,7 +138,7 @@
   // Makes `*this` equivalent to a newly constructed `StdErr`. This avoids
   // constructing a temporary `StdErr` and moving from it.
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Closed);
-  ABSL_ATTRIBUTE_REINITIALIZES void Reset(Options options = Options());
+  ABSL_ATTRIBUTE_REINITIALIZES void Reset(const Options& options = Options());
 };
 
 // Sets file descriptors used by future instances of `Std{In,Out,Err}` in the
diff --git a/riegeli/bytes/string_writer.h b/riegeli/bytes/string_writer.h
index df8985d..00809d6 100644
--- a/riegeli/bytes/string_writer.h
+++ b/riegeli/bytes/string_writer.h
@@ -51,6 +51,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // If `false`, replaces existing contents of the destination, clearing it
     // first.
     //
@@ -395,7 +398,7 @@
 template <typename DependentDest,
           std::enable_if_t<std::is_same_v<DependentDest, std::string>, int>>
 inline StringWriter<Dest>::StringWriter(Options options)
-    : StringWriter(riegeli::Maker(), std::move(options)) {}
+    : StringWriter(riegeli::Maker(), options) {}
 
 template <typename Dest>
 inline void StringWriter<Dest>::Reset(Closed) {
@@ -414,7 +417,7 @@
 template <typename DependentDest,
           std::enable_if_t<std::is_same_v<DependentDest, std::string>, int>>
 inline void StringWriter<Dest>::Reset(Options options) {
-  Reset(riegeli::Maker(), std::move(options));
+  Reset(riegeli::Maker(), options);
 }
 
 }  // namespace riegeli
diff --git a/riegeli/bytes/writer_cfile.h b/riegeli/bytes/writer_cfile.h
index 9cbd020..22ca38d 100644
--- a/riegeli/bytes/writer_cfile.h
+++ b/riegeli/bytes/writer_cfile.h
@@ -44,6 +44,12 @@
  public:
   WriterCFileOptions() noexcept {}
 
+  WriterCFileOptions(const WriterCFileOptions& that) = default;
+  WriterCFileOptions& operator=(const WriterCFileOptions& that) = default;
+
+  WriterCFileOptions(WriterCFileOptions&& that) = default;
+  WriterCFileOptions& operator=(WriterCFileOptions&& that) = default;
+
   // The filename assumed by the returned `OwnedCFile`.
   //
   // Default: "<unspecified>".
diff --git a/riegeli/bytes/writer_ostream.h b/riegeli/bytes/writer_ostream.h
index 2e5c89c..e24db9e 100644
--- a/riegeli/bytes/writer_ostream.h
+++ b/riegeli/bytes/writer_ostream.h
@@ -105,6 +105,9 @@
   class Options {
    public:
     Options() noexcept {}
+
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
   };
 
   // Returns the `Writer`. Unchanged by `close()`.
diff --git a/riegeli/bzip2/bzip2_reader.h b/riegeli/bzip2/bzip2_reader.h
index 8a94b3f..fc7c596 100644
--- a/riegeli/bzip2/bzip2_reader.h
+++ b/riegeli/bzip2/bzip2_reader.h
@@ -43,6 +43,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // If `true`, concatenated compressed streams are decoded to concatenation
     // of their decompressed contents. An empty compressed stream is decoded to
     // empty decompressed contents.
diff --git a/riegeli/bzip2/bzip2_writer.h b/riegeli/bzip2/bzip2_writer.h
index 824163f..367ae80 100644
--- a/riegeli/bzip2/bzip2_writer.h
+++ b/riegeli/bzip2/bzip2_writer.h
@@ -41,6 +41,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // Tunes the tradeoff between compression density and compression speed
     // (higher = better density but slower).
     //
diff --git a/riegeli/chunk_encoding/brotli_encoder_selection.cc b/riegeli/chunk_encoding/brotli_encoder_selection.cc
index ad90e3b..54b246d 100644
--- a/riegeli/chunk_encoding/brotli_encoder_selection.cc
+++ b/riegeli/chunk_encoding/brotli_encoder_selection.cc
@@ -32,7 +32,7 @@
 
 ABSL_ATTRIBUTE_WEAK std::unique_ptr<Writer> NewBrotliWriter(
     Chain* compressed, const CompressorOptions& compressor_options,
-    const RecyclingPoolOptions& /*recycling_pool_options*/) {
+    RecyclingPoolOptions /*recycling_pool_options*/) {
   switch (compressor_options.brotli_encoder()) {
     case BrotliEncoder::kRBrotliOrCBrotli:
     case BrotliEncoder::kCBrotli:
diff --git a/riegeli/chunk_encoding/brotli_encoder_selection.h b/riegeli/chunk_encoding/brotli_encoder_selection.h
index 5db9846..9e4bb4b 100644
--- a/riegeli/chunk_encoding/brotli_encoder_selection.h
+++ b/riegeli/chunk_encoding/brotli_encoder_selection.h
@@ -34,7 +34,7 @@
 // It can be overridden to support also Rust Brotli.
 std::unique_ptr<Writer> NewBrotliWriter(
     Chain* compressed, const CompressorOptions& compressor_options,
-    const RecyclingPoolOptions& recycling_pool_options);
+    RecyclingPoolOptions recycling_pool_options);
 
 // Support for `NewBrotliWriter()`: uses C Brotli, ignores
 // `compressor_options.brotli_encoder()`.
diff --git a/riegeli/chunk_encoding/chunk_decoder.h b/riegeli/chunk_encoding/chunk_decoder.h
index 7a73925..3b306de 100644
--- a/riegeli/chunk_encoding/chunk_decoder.h
+++ b/riegeli/chunk_encoding/chunk_decoder.h
@@ -50,6 +50,12 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
+    Options(Options&& that) = default;
+    Options& operator=(Options&& that) = default;
+
     // Specifies the set of fields to be included in returned records, allowing
     // to exclude the remaining fields (but does not guarantee exclusion).
     // Excluding data makes reading faster.
@@ -92,13 +98,13 @@
     //
     // Default: `RecyclingPoolOptions()`.
     Options& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &
+        RecyclingPoolOptions recycling_pool_options) &
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       recycling_pool_options_ = recycling_pool_options;
       return *this;
     }
     Options&& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &&
+        RecyclingPoolOptions recycling_pool_options) &&
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       return std::move(set_recycling_pool_options(recycling_pool_options));
     }
diff --git a/riegeli/chunk_encoding/compressor.cc b/riegeli/chunk_encoding/compressor.cc
index d87f2a9..0dd39f4 100644
--- a/riegeli/chunk_encoding/compressor.cc
+++ b/riegeli/chunk_encoding/compressor.cc
@@ -40,14 +40,13 @@
 
 Compressor::Compressor(CompressorOptions compressor_options,
                        TuningOptions tuning_options)
-    : compressor_options_(std::move(compressor_options)),
-      tuning_options_(std::move(tuning_options)) {
+    : compressor_options_(compressor_options), tuning_options_(tuning_options) {
   Initialize();
   SetWriteSizeHint();
 }
 
 void Compressor::Clear(TuningOptions tuning_options) {
-  tuning_options_ = std::move(tuning_options);
+  tuning_options_ = tuning_options;
   Clear();
 }
 
diff --git a/riegeli/chunk_encoding/compressor.h b/riegeli/chunk_encoding/compressor.h
index ab89e3e..b8fb5d1 100644
--- a/riegeli/chunk_encoding/compressor.h
+++ b/riegeli/chunk_encoding/compressor.h
@@ -36,6 +36,9 @@
    public:
     TuningOptions() noexcept {}
 
+    TuningOptions(const TuningOptions& that) = default;
+    TuningOptions& operator=(const TuningOptions& that) = default;
+
     // Exact uncompressed size, or `std::nullopt` if unknown. This may improve
     // compression density and performance, and may cause the size to be stored
     // in the compressed stream header.
@@ -80,13 +83,13 @@
     //
     // Default: `RecyclingPoolOptions()`.
     TuningOptions& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &
+        RecyclingPoolOptions recycling_pool_options) &
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       recycling_pool_options_ = recycling_pool_options;
       return *this;
     }
     TuningOptions&& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &&
+        RecyclingPoolOptions recycling_pool_options) &&
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       return std::move(set_recycling_pool_options(recycling_pool_options));
     }
diff --git a/riegeli/chunk_encoding/compressor_options.h b/riegeli/chunk_encoding/compressor_options.h
index 74d721c..9092397 100644
--- a/riegeli/chunk_encoding/compressor_options.h
+++ b/riegeli/chunk_encoding/compressor_options.h
@@ -44,6 +44,9 @@
  public:
   CompressorOptions() noexcept {}
 
+  CompressorOptions(const CompressorOptions& that) = default;
+  CompressorOptions& operator=(const CompressorOptions& that) = default;
+
   // Parses options from text:
   // ```
   //   options ::= option? ("," option?)*
diff --git a/riegeli/chunk_encoding/decompressor.h b/riegeli/chunk_encoding/decompressor.h
index c3e28fe..3397871 100644
--- a/riegeli/chunk_encoding/decompressor.h
+++ b/riegeli/chunk_encoding/decompressor.h
@@ -56,6 +56,9 @@
  public:
   DecompressorOptions() noexcept {}
 
+  DecompressorOptions(const DecompressorOptions& that) = default;
+  DecompressorOptions& operator=(const DecompressorOptions& that) = default;
+
   // Options for a global `RecyclingPool` of decompression contexts.
   //
   // They tune the amount of memory which is kept to speed up creation of new
@@ -63,13 +66,13 @@
   //
   // Default: `RecyclingPoolOptions()`.
   DecompressorOptions& set_recycling_pool_options(
-      const RecyclingPoolOptions& recycling_pool_options) &
+      RecyclingPoolOptions recycling_pool_options) &
       ABSL_ATTRIBUTE_LIFETIME_BOUND {
     recycling_pool_options_ = recycling_pool_options;
     return *this;
   }
   DecompressorOptions&& set_recycling_pool_options(
-      const RecyclingPoolOptions& recycling_pool_options) &&
+      RecyclingPoolOptions recycling_pool_options) &&
       ABSL_ATTRIBUTE_LIFETIME_BOUND {
     return std::move(set_recycling_pool_options(recycling_pool_options));
   }
@@ -134,7 +137,7 @@
 
  private:
   void Initialize(Initializer<Src> src, CompressionType compression_type,
-                  const RecyclingPoolOptions& recycling_pool_options);
+                  RecyclingPoolOptions recycling_pool_options);
 
   Any<Reader*>::Inlining<Src, BrotliReader<Src>, ZstdReader<Src>,
                          SnappyReader<Src>>
@@ -169,7 +172,7 @@
 template <typename Src>
 inline void Decompressor<Src>::Initialize(
     Initializer<Src> src, CompressionType compression_type,
-    const RecyclingPoolOptions& recycling_pool_options) {
+    RecyclingPoolOptions recycling_pool_options) {
   if (compression_type == CompressionType::kNone) {
     decompressed_ = std::move(src);
     return;
diff --git a/riegeli/chunk_encoding/simple_decoder.h b/riegeli/chunk_encoding/simple_decoder.h
index e2528b6..4fdd1dd 100644
--- a/riegeli/chunk_encoding/simple_decoder.h
+++ b/riegeli/chunk_encoding/simple_decoder.h
@@ -36,6 +36,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // Options for a global `RecyclingPool` of decompression contexts.
     //
     // They tune the amount of memory which is kept to speed up creation of new
@@ -43,13 +46,13 @@
     //
     // Default: `RecyclingPoolOptions()`.
     Options& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &
+        RecyclingPoolOptions recycling_pool_options) &
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       recycling_pool_options_ = recycling_pool_options;
       return *this;
     }
     Options&& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &&
+        RecyclingPoolOptions recycling_pool_options) &&
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       return std::move(set_recycling_pool_options(recycling_pool_options));
     }
diff --git a/riegeli/chunk_encoding/simple_encoder.h b/riegeli/chunk_encoding/simple_encoder.h
index f5856e1..f81dc08 100644
--- a/riegeli/chunk_encoding/simple_encoder.h
+++ b/riegeli/chunk_encoding/simple_encoder.h
@@ -55,6 +55,9 @@
    public:
     TuningOptions() noexcept {}
 
+    TuningOptions(const TuningOptions& that) = default;
+    TuningOptions& operator=(const TuningOptions& that) = default;
+
     // Expected uncompressed size of concatenated values, or `std::nullopt` if
     // unknown. This may improve compression density and performance.
     //
@@ -79,13 +82,13 @@
     //
     // Default: `RecyclingPoolOptions()`.
     TuningOptions& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &
+        RecyclingPoolOptions recycling_pool_options) &
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       recycling_pool_options_ = recycling_pool_options;
       return *this;
     }
     TuningOptions&& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &&
+        RecyclingPoolOptions recycling_pool_options) &&
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       return std::move(set_recycling_pool_options(recycling_pool_options));
     }
diff --git a/riegeli/chunk_encoding/transpose_decoder.h b/riegeli/chunk_encoding/transpose_decoder.h
index 9111831..1f9c75a 100644
--- a/riegeli/chunk_encoding/transpose_decoder.h
+++ b/riegeli/chunk_encoding/transpose_decoder.h
@@ -39,6 +39,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // Options for a global `RecyclingPool` of decompression contexts.
     //
     // They tune the amount of memory which is kept to speed up creation of new
@@ -46,13 +49,13 @@
     //
     // Default: `RecyclingPoolOptions()`.
     Options& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &
+        RecyclingPoolOptions recycling_pool_options) &
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       recycling_pool_options_ = recycling_pool_options;
       return *this;
     }
     Options&& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &&
+        RecyclingPoolOptions recycling_pool_options) &&
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       return std::move(set_recycling_pool_options(recycling_pool_options));
     }
diff --git a/riegeli/chunk_encoding/transpose_encoder.cc b/riegeli/chunk_encoding/transpose_encoder.cc
index c5794fe..8f684d1 100644
--- a/riegeli/chunk_encoding/transpose_encoder.cc
+++ b/riegeli/chunk_encoding/transpose_encoder.cc
@@ -197,7 +197,7 @@
 
 TransposeEncoder::TransposeEncoder(CompressorOptions compressor_options,
                                    TuningOptions tuning_options)
-    : compressor_options_(std::move(compressor_options)),
+    : compressor_options_(compressor_options),
       bucket_size_(compressor_options_.compression_type() ==
                            CompressionType::kNone
                        ? std::numeric_limits<uint64_t>::max()
diff --git a/riegeli/chunk_encoding/transpose_encoder.h b/riegeli/chunk_encoding/transpose_encoder.h
index 8a7b39a..46cb336 100644
--- a/riegeli/chunk_encoding/transpose_encoder.h
+++ b/riegeli/chunk_encoding/transpose_encoder.h
@@ -74,6 +74,9 @@
    public:
     TuningOptions() noexcept {}
 
+    TuningOptions(const TuningOptions& that) = default;
+    TuningOptions& operator=(const TuningOptions& that) = default;
+
     // The default approximate bucket size, used if compression is enabled.
     // Finer bucket granularity (i.e. smaller size) worsens compression density
     // but makes field projection more effective.
@@ -97,13 +100,13 @@
     //
     // Default: `RecyclingPoolOptions()`.
     TuningOptions& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &
+        RecyclingPoolOptions recycling_pool_options) &
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       recycling_pool_options_ = recycling_pool_options;
       return *this;
     }
     TuningOptions&& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &&
+        RecyclingPoolOptions recycling_pool_options) &&
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       return std::move(set_recycling_pool_options(recycling_pool_options));
     }
diff --git a/riegeli/containers/chunked_sorted_string_set.cc b/riegeli/containers/chunked_sorted_string_set.cc
index 411bd0f..5f8b097 100644
--- a/riegeli/containers/chunked_sorted_string_set.cc
+++ b/riegeli/containers/chunked_sorted_string_set.cc
@@ -43,12 +43,12 @@
 
 ChunkedSortedStringSet ChunkedSortedStringSet::FromSorted(
     std::initializer_list<absl::string_view> src, Options options) {
-  return FromSorted<>(src, std::move(options));
+  return FromSorted<>(src, options);
 }
 
 ChunkedSortedStringSet ChunkedSortedStringSet::FromUnsorted(
     std::initializer_list<absl::string_view> src, Options options) {
-  return FromUnsorted<>(src, std::move(options));
+  return FromUnsorted<>(src, options);
 }
 
 inline ChunkedSortedStringSet::ChunkedSortedStringSet(Chunks&& chunks)
diff --git a/riegeli/containers/chunked_sorted_string_set.h b/riegeli/containers/chunked_sorted_string_set.h
index 65d080a..9121444 100644
--- a/riegeli/containers/chunked_sorted_string_set.h
+++ b/riegeli/containers/chunked_sorted_string_set.h
@@ -58,6 +58,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // Tunes the number of elements encoded together. A larger `chunk_size`
     // reduces memory usage, but the time complexity of lookups is roughly
     // proportional to `chunk_size`.
@@ -106,6 +109,9 @@
    public:
     DecodeOptions() noexcept {}
 
+    DecodeOptions(const DecodeOptions& that) = default;
+    DecodeOptions& operator=(const DecodeOptions& that) = default;
+
     // If `false`, performs partial validation of the structure of data, which
     // is sufficient to prevent undefined behavior when the set is used. The
     // only aspect not validated is that elements are sorted and unique. This is
@@ -658,7 +664,7 @@
   if (IsRandomAccessIterable<Src>::value) {
     options.set_size_hint(std::distance(iter, end_iter));
   }
-  ChunkedSortedStringSet::Builder builder(std::move(options));
+  ChunkedSortedStringSet::Builder builder(options);
   for (; iter != end_iter; ++iter) {
     builder.InsertNext(*MaybeMakeMoveIterator<Src>(iter));
   }
@@ -686,7 +692,7 @@
             });
 
   options.set_size_hint(iterators.size());
-  ChunkedSortedStringSet::Builder builder(std::move(options));
+  ChunkedSortedStringSet::Builder builder(options);
   for (const SrcIterator& iter : iterators) {
     builder.InsertNext(*MaybeMakeMoveIterator<Src>(iter));
   }
diff --git a/riegeli/containers/linear_sorted_string_set.h b/riegeli/containers/linear_sorted_string_set.h
index 152eaa7..b7c6ee2 100644
--- a/riegeli/containers/linear_sorted_string_set.h
+++ b/riegeli/containers/linear_sorted_string_set.h
@@ -76,6 +76,9 @@
    public:
     DecodeOptions() noexcept {}
 
+    DecodeOptions(const DecodeOptions& that) = default;
+    DecodeOptions& operator=(const DecodeOptions& that) = default;
+
     // If `false`, performs partial validation of the structure of data, which
     // is sufficient to prevent undefined behavior when the set is used. The
     // only aspect not validated is that elements are sorted and unique. This is
diff --git a/riegeli/csv/csv_reader.h b/riegeli/csv/csv_reader.h
index 32adf75..fdaead5 100644
--- a/riegeli/csv/csv_reader.h
+++ b/riegeli/csv/csv_reader.h
@@ -57,6 +57,12 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
+    Options(Options&& that) = default;
+    Options& operator=(Options&& that) = default;
+
     // If not `std::nullopt`, automatically reads field names from the first
     // record, specifies how field names are normalized, and verifies that all
     // required fields are present (in any order).
diff --git a/riegeli/csv/csv_writer.h b/riegeli/csv/csv_writer.h
index 71bbcb8..1891aa3 100644
--- a/riegeli/csv/csv_writer.h
+++ b/riegeli/csv/csv_writer.h
@@ -61,6 +61,12 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
+    Options(Options&& that) = default;
+    Options& operator=(Options&& that) = default;
+
     // If not `std::nullopt`, sets field names, and automatically writes them
     // as the first record.
     //
diff --git a/riegeli/gcs/gcs_reader.h b/riegeli/gcs/gcs_reader.h
index 829da33..5024fa0 100644
--- a/riegeli/gcs/gcs_reader.h
+++ b/riegeli/gcs/gcs_reader.h
@@ -56,6 +56,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     static constexpr size_t kDefaultMinBufferSize = size_t{64} << 10;
     static constexpr size_t kDefaultMaxBufferSize = size_t{1} << 20;
   };
@@ -172,8 +175,7 @@
   }
 
   template <typename... ReadObjectOptions>
-  void Initialize(const Options& options,
-                  ReadObjectOptions&&... read_object_options);
+  void Initialize(Options options, ReadObjectOptions&&... read_object_options);
   void Initialize(google::cloud::storage::ObjectReadStream stream,
                   BufferOptions buffer_options,
                   const RangeOptions& range_options);
@@ -238,7 +240,7 @@
 }
 
 template <typename... ReadObjectOptions>
-inline void GcsReader::Initialize(const Options& options,
+inline void GcsReader::Initialize(Options options,
                                   ReadObjectOptions&&... read_object_options) {
   if (ABSL_PREDICT_FALSE(!object_.ok())) {
     Fail(object_.status());
diff --git a/riegeli/gcs/gcs_writer.h b/riegeli/gcs/gcs_writer.h
index 5134d9e..fa25750 100644
--- a/riegeli/gcs/gcs_writer.h
+++ b/riegeli/gcs/gcs_writer.h
@@ -66,6 +66,12 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
+    Options(Options&& that) = default;
+    Options& operator=(Options&& that) = default;
+
     // The effective buffer size is always a multiple of 256 KiB, and is at
     // least the `UploadBufferSize` setting in the client (which defaults to
     // 8 MiB).
diff --git a/riegeli/lines/line_reading.h b/riegeli/lines/line_reading.h
index 2721d56..b0093e6 100644
--- a/riegeli/lines/line_reading.h
+++ b/riegeli/lines/line_reading.h
@@ -35,6 +35,9 @@
  public:
   ReadLineOptions() noexcept {}
 
+  ReadLineOptions(const ReadLineOptions& that) = default;
+  ReadLineOptions& operator=(const ReadLineOptions& that) = default;
+
   // Options can also be specified by the line terminator alone.
   /*implicit*/ ReadLineOptions(ReadNewline newline) : newline_(newline) {}
 
diff --git a/riegeli/lines/line_writing.h b/riegeli/lines/line_writing.h
index cd49723..0914280 100644
--- a/riegeli/lines/line_writing.h
+++ b/riegeli/lines/line_writing.h
@@ -36,6 +36,9 @@
  public:
   WriteLineOptions() noexcept {}
 
+  WriteLineOptions(const WriteLineOptions& that) = default;
+  WriteLineOptions& operator=(const WriteLineOptions& that) = default;
+
   // Options can also be specified by the line terminator alone.
   /*implicit*/ WriteLineOptions(WriteNewline newline) : newline_(newline) {}
 
diff --git a/riegeli/lines/text_reader.h b/riegeli/lines/text_reader.h
index c9aaabf..73fe79e 100644
--- a/riegeli/lines/text_reader.h
+++ b/riegeli/lines/text_reader.h
@@ -198,6 +198,9 @@
  public:
   AnyTextReaderOptions() noexcept {}
 
+  AnyTextReaderOptions(const AnyTextReaderOptions& that) = default;
+  AnyTextReaderOptions& operator=(const AnyTextReaderOptions& that) = default;
+
   // Line terminator representation to translate from LF.
   //
   // Default: `ReadNewline::kCrLfOrLf`.
diff --git a/riegeli/lines/text_writer.h b/riegeli/lines/text_writer.h
index 55286ef..dd31b63 100644
--- a/riegeli/lines/text_writer.h
+++ b/riegeli/lines/text_writer.h
@@ -163,6 +163,9 @@
  public:
   AnyTextWriterOptions() noexcept {}
 
+  AnyTextWriterOptions(const AnyTextWriterOptions& that) = default;
+  AnyTextWriterOptions& operator=(const AnyTextWriterOptions& that) = default;
+
   // Line terminator representation to translate from LF.
   //
   // Default: `WriteNewline::kNative`.
diff --git a/riegeli/lz4/lz4_reader.cc b/riegeli/lz4/lz4_reader.cc
index e2d30a1..92520ef 100644
--- a/riegeli/lz4/lz4_reader.cc
+++ b/riegeli/lz4/lz4_reader.cc
@@ -336,7 +336,7 @@
 namespace lz4_internal {
 
 inline bool GetFrameInfo(Reader& src, LZ4F_frameInfo_t& frame_info,
-                         const RecyclingPoolOptions& recycling_pool_options) {
+                         RecyclingPoolOptions recycling_pool_options) {
   using LZ4F_dctxDeleter = Lz4ReaderBase::LZ4F_dctxDeleter;
   RecyclingPool<LZ4F_dctx, LZ4F_dctxDeleter>::Handle decompressor;
   {
@@ -372,14 +372,13 @@
 
 }  // namespace lz4_internal
 
-bool RecognizeLz4(Reader& src,
-                  const RecyclingPoolOptions& recycling_pool_options) {
+bool RecognizeLz4(Reader& src, RecyclingPoolOptions recycling_pool_options) {
   LZ4F_frameInfo_t frame_info;
   return lz4_internal::GetFrameInfo(src, frame_info, recycling_pool_options);
 }
 
 std::optional<Position> Lz4UncompressedSize(
-    Reader& src, const RecyclingPoolOptions& recycling_pool_options) {
+    Reader& src, RecyclingPoolOptions recycling_pool_options) {
   LZ4F_frameInfo_t frame_info;
   if (!lz4_internal::GetFrameInfo(src, frame_info, recycling_pool_options)) {
     return std::nullopt;
diff --git a/riegeli/lz4/lz4_reader.h b/riegeli/lz4/lz4_reader.h
index c7e3174..c4167f0 100644
--- a/riegeli/lz4/lz4_reader.h
+++ b/riegeli/lz4/lz4_reader.h
@@ -42,7 +42,7 @@
 namespace lz4_internal {
 
 bool GetFrameInfo(Reader& src, LZ4F_frameInfo_t& frame_info,
-                  const RecyclingPoolOptions& recycling_pool_options);
+                  RecyclingPoolOptions recycling_pool_options);
 
 }  // namespace lz4_internal
 
@@ -53,6 +53,12 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
+    Options(Options&& that) = default;
+    Options& operator=(Options&& that) = default;
+
     // If `true`, supports decompressing as much as possible from a truncated
     // source, then retrying when the source has grown. This has a small
     // performance penalty.
@@ -114,13 +120,13 @@
     //
     // Default: `RecyclingPoolOptions()`.
     Options& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &
+        RecyclingPoolOptions recycling_pool_options) &
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       recycling_pool_options_ = recycling_pool_options;
       return *this;
     }
     Options&& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &&
+        RecyclingPoolOptions recycling_pool_options) &&
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       return std::move(set_recycling_pool_options(recycling_pool_options));
     }
@@ -165,7 +171,7 @@
 
   explicit Lz4ReaderBase(BufferOptions buffer_options, bool growing_source,
                          bool concatenate, Lz4Dictionary&& dictionary,
-                         const RecyclingPoolOptions& recycling_pool_options);
+                         RecyclingPoolOptions recycling_pool_options);
 
   Lz4ReaderBase(Lz4ReaderBase&& that) noexcept;
   Lz4ReaderBase& operator=(Lz4ReaderBase&& that) noexcept;
@@ -173,7 +179,7 @@
   void Reset(Closed);
   void Reset(BufferOptions buffer_options, bool growing_source,
              bool concatenate, Lz4Dictionary&& dictionary,
-             const RecyclingPoolOptions& recycling_pool_options);
+             RecyclingPoolOptions recycling_pool_options);
   void Initialize(Reader* src);
   ABSL_ATTRIBUTE_COLD absl::Status AnnotateOverSrc(absl::Status status);
 
@@ -189,7 +195,7 @@
   // For `LZ4F_dctxDeleter`.
   friend bool lz4_internal::GetFrameInfo(
       Reader& src, LZ4F_frameInfo_t& frame_info,
-      const RecyclingPoolOptions& recycling_pool_options);
+      RecyclingPoolOptions recycling_pool_options);
 
   struct LZ4F_dctxDeleter {
     void operator()(LZ4F_dctx* ptr) const {
@@ -283,9 +289,8 @@
 // Returns `true` if the data look like they have been Lz4-compressed.
 //
 // The current position of `src` is unchanged.
-bool RecognizeLz4(Reader& src,
-                  const RecyclingPoolOptions& recycling_pool_options =
-                      RecyclingPoolOptions());
+bool RecognizeLz4(Reader& src, RecyclingPoolOptions recycling_pool_options =
+                                   RecyclingPoolOptions());
 
 // Returns the claimed uncompressed size of Lz4-compressed data.
 //
@@ -296,15 +301,15 @@
 //
 // The current position of `src` is unchanged.
 std::optional<Position> Lz4UncompressedSize(
-    Reader& src, const RecyclingPoolOptions& recycling_pool_options =
-                     RecyclingPoolOptions());
+    Reader& src,
+    RecyclingPoolOptions recycling_pool_options = RecyclingPoolOptions());
 
 // Implementation details follow.
 
-inline Lz4ReaderBase::Lz4ReaderBase(
-    BufferOptions buffer_options, bool growing_source, bool concatenate,
-    Lz4Dictionary&& dictionary,
-    const RecyclingPoolOptions& recycling_pool_options)
+inline Lz4ReaderBase::Lz4ReaderBase(BufferOptions buffer_options,
+                                    bool growing_source, bool concatenate,
+                                    Lz4Dictionary&& dictionary,
+                                    RecyclingPoolOptions recycling_pool_options)
     : BufferedReader(buffer_options),
       growing_source_(growing_source),
       concatenate_(concatenate),
@@ -347,10 +352,10 @@
   dictionary_ = Lz4Dictionary();
 }
 
-inline void Lz4ReaderBase::Reset(
-    BufferOptions buffer_options, bool growing_source, bool concatenate,
-    Lz4Dictionary&& dictionary,
-    const RecyclingPoolOptions& recycling_pool_options) {
+inline void Lz4ReaderBase::Reset(BufferOptions buffer_options,
+                                 bool growing_source, bool concatenate,
+                                 Lz4Dictionary&& dictionary,
+                                 RecyclingPoolOptions recycling_pool_options) {
   BufferedReader::Reset(buffer_options);
   growing_source_ = growing_source;
   concatenate_ = concatenate;
diff --git a/riegeli/lz4/lz4_writer.h b/riegeli/lz4/lz4_writer.h
index f51edec..ea3883d 100644
--- a/riegeli/lz4/lz4_writer.h
+++ b/riegeli/lz4/lz4_writer.h
@@ -53,6 +53,12 @@
           << "Unexpected value of LZ4F_compressionLevel_max()";
     }
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
+    Options(Options&& that) = default;
+    Options& operator=(Options&& that) = default;
+
     // Tunes the tradeoff between compression density and compression speed
     // (higher = better density but slower).
     //
@@ -220,13 +226,13 @@
     //
     // Default: `RecyclingPoolOptions()`.
     Options& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &
+        RecyclingPoolOptions recycling_pool_options) &
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       recycling_pool_options_ = recycling_pool_options;
       return *this;
     }
     Options&& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &&
+        RecyclingPoolOptions recycling_pool_options) &&
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       return std::move(set_recycling_pool_options(recycling_pool_options));
     }
@@ -258,7 +264,7 @@
                          Lz4Dictionary&& dictionary,
                          std::optional<Position> pledged_size,
                          bool reserve_max_size,
-                         const RecyclingPoolOptions& recycling_pool_options);
+                         RecyclingPoolOptions recycling_pool_options);
 
   Lz4WriterBase(Lz4WriterBase&& that) noexcept;
   Lz4WriterBase& operator=(Lz4WriterBase&& that) noexcept;
@@ -266,7 +272,7 @@
   void Reset(Closed);
   void Reset(BufferOptions buffer_options, Lz4Dictionary&& dictionary,
              std::optional<Position> pledged_size, bool reserve_max_size,
-             const RecyclingPoolOptions& recycling_pool_options);
+             RecyclingPoolOptions recycling_pool_options);
   void Initialize(Writer* dest, int compression_level, int window_log,
                   bool store_content_checksum, bool store_block_checksum);
   ABSL_ATTRIBUTE_COLD absl::Status AnnotateOverDest(absl::Status status);
@@ -369,10 +375,11 @@
 
 // Implementation details follow.
 
-inline Lz4WriterBase::Lz4WriterBase(
-    BufferOptions buffer_options, Lz4Dictionary&& dictionary,
-    std::optional<Position> pledged_size, bool reserve_max_size,
-    const RecyclingPoolOptions& recycling_pool_options)
+inline Lz4WriterBase::Lz4WriterBase(BufferOptions buffer_options,
+                                    Lz4Dictionary&& dictionary,
+                                    std::optional<Position> pledged_size,
+                                    bool reserve_max_size,
+                                    RecyclingPoolOptions recycling_pool_options)
     : BufferedWriter(buffer_options),
       dictionary_(std::move(dictionary)),
       pledged_size_(pledged_size),
@@ -422,10 +429,11 @@
   associated_reader_.Reset();
 }
 
-inline void Lz4WriterBase::Reset(
-    BufferOptions buffer_options, Lz4Dictionary&& dictionary,
-    std::optional<Position> pledged_size, bool reserve_max_size,
-    const RecyclingPoolOptions& recycling_pool_options) {
+inline void Lz4WriterBase::Reset(BufferOptions buffer_options,
+                                 Lz4Dictionary&& dictionary,
+                                 std::optional<Position> pledged_size,
+                                 bool reserve_max_size,
+                                 RecyclingPoolOptions recycling_pool_options) {
   BufferedWriter::Reset(buffer_options);
   pledged_size_ = pledged_size;
   reserve_max_size_ = reserve_max_size;
diff --git a/riegeli/messages/parse_message.h b/riegeli/messages/parse_message.h
index a5d0fd2..d837bf2 100644
--- a/riegeli/messages/parse_message.h
+++ b/riegeli/messages/parse_message.h
@@ -42,6 +42,9 @@
  public:
   ParseMessageOptions() noexcept {}
 
+  ParseMessageOptions(const ParseMessageOptions& that) = default;
+  ParseMessageOptions& operator=(const ParseMessageOptions& that) = default;
+
   // If `false`, replaces existing contents of the destination, clearing it
   // first.
   //
diff --git a/riegeli/messages/serialize_message.h b/riegeli/messages/serialize_message.h
index 9286f88..391636f 100644
--- a/riegeli/messages/serialize_message.h
+++ b/riegeli/messages/serialize_message.h
@@ -45,6 +45,10 @@
  public:
   SerializeMessageOptions() noexcept {}
 
+  SerializeMessageOptions(const SerializeMessageOptions& that) = default;
+  SerializeMessageOptions& operator=(const SerializeMessageOptions& that) =
+      default;
+
   // If `false`, all required fields must be set. This is verified in debug
   // mode.
   //
diff --git a/riegeli/messages/text_parse_message.h b/riegeli/messages/text_parse_message.h
index d1bd242..920d310 100644
--- a/riegeli/messages/text_parse_message.h
+++ b/riegeli/messages/text_parse_message.h
@@ -59,6 +59,9 @@
  public:
   TextParseMessageOptions();
 
+  TextParseMessageOptions(TextParseMessageOptions&& that) = default;
+  TextParseMessageOptions& operator=(TextParseMessageOptions&& that) = default;
+
   // If `false`, replaces existing contents of the destination, clearing it
   // first.
   //
diff --git a/riegeli/messages/text_print_message.h b/riegeli/messages/text_print_message.h
index 9ef22a4..a97961f 100644
--- a/riegeli/messages/text_print_message.h
+++ b/riegeli/messages/text_print_message.h
@@ -35,6 +35,9 @@
  public:
   TextPrintMessageOptions() noexcept {}
 
+  TextPrintMessageOptions(TextPrintMessageOptions&& that) = default;
+  TextPrintMessageOptions& operator=(TextPrintMessageOptions&& that) = default;
+
   // If `false`, all required fields must be set. This is verified in debug
   // mode.
   //
diff --git a/riegeli/records/chunk_writer.h b/riegeli/records/chunk_writer.h
index c72e9b4..ba4cfc9 100644
--- a/riegeli/records/chunk_writer.h
+++ b/riegeli/records/chunk_writer.h
@@ -123,6 +123,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // File position assumed initially.
     //
     // This can be used to prepare a file fragment which can be appended to the
diff --git a/riegeli/records/record_reader.h b/riegeli/records/record_reader.h
index 88648b6..7ec3794 100644
--- a/riegeli/records/record_reader.h
+++ b/riegeli/records/record_reader.h
@@ -85,6 +85,12 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
+    Options(Options&& that) = default;
+    Options& operator=(Options&& that) = default;
+
     // Specifies the set of fields to be included in returned records, allowing
     // to exclude the remaining fields (but does not guarantee that they will be
     // excluded). Excluding data makes reading faster.
@@ -184,13 +190,13 @@
     //
     // Default: `RecyclingPoolOptions()`.
     Options& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &
+        RecyclingPoolOptions recycling_pool_options) &
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       recycling_pool_options_ = recycling_pool_options;
       return *this;
     }
     Options&& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &&
+        RecyclingPoolOptions recycling_pool_options) &&
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       return std::move(set_recycling_pool_options(recycling_pool_options));
     }
diff --git a/riegeli/records/record_writer.cc b/riegeli/records/record_writer.cc
index 23ac9f2..89a1429 100644
--- a/riegeli/records/record_writer.cc
+++ b/riegeli/records/record_writer.cc
@@ -354,7 +354,7 @@
     SerializeMessageOptions serialize_options) {
   if (ABSL_PREDICT_FALSE(!ok())) return false;
   if (ABSL_PREDICT_FALSE(
-          !chunk_encoder_->AddRecord(record, std::move(serialize_options)))) {
+          !chunk_encoder_->AddRecord(record, serialize_options))) {
     return Fail(chunk_encoder_->status());
   }
   return true;
@@ -931,7 +931,7 @@
                                    SerializeMessageOptions serialize_options) {
   if (ABSL_PREDICT_FALSE(!ok())) return false;
   const size_t size = serialize_options.GetByteSize(record);
-  return WriteRecordImpl(size, record, std::move(serialize_options));
+  return WriteRecordImpl(size, record, serialize_options);
 }
 
 bool RecordWriterBase::WriteRecord(BytesRef record) {
diff --git a/riegeli/records/record_writer.h b/riegeli/records/record_writer.h
index 50eafeb..5f501c9 100644
--- a/riegeli/records/record_writer.h
+++ b/riegeli/records/record_writer.h
@@ -71,6 +71,12 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
+    Options(Options&& that) = default;
+    Options& operator=(Options&& that) = default;
+
     // Parses options from text:
     // ```
     //   options ::= option? ("," option?)*
@@ -476,13 +482,13 @@
     //
     // Default: `RecyclingPoolOptions()`.
     Options& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &
+        RecyclingPoolOptions recycling_pool_options) &
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       recycling_pool_options_ = recycling_pool_options;
       return *this;
     }
     Options&& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &&
+        RecyclingPoolOptions recycling_pool_options) &&
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       return std::move(set_recycling_pool_options(recycling_pool_options));
     }
diff --git a/riegeli/snappy/framed/framed_snappy_writer.h b/riegeli/snappy/framed/framed_snappy_writer.h
index 2ae1d89..d2c70f8 100644
--- a/riegeli/snappy/framed/framed_snappy_writer.h
+++ b/riegeli/snappy/framed/framed_snappy_writer.h
@@ -46,6 +46,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // Tunes the tradeoff between compression density and compression speed
     // (higher = better density but slower).
     //
diff --git a/riegeli/snappy/hadoop/hadoop_snappy_writer.h b/riegeli/snappy/hadoop/hadoop_snappy_writer.h
index 612318c..5cb2e2a 100644
--- a/riegeli/snappy/hadoop/hadoop_snappy_writer.h
+++ b/riegeli/snappy/hadoop/hadoop_snappy_writer.h
@@ -46,6 +46,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // Tunes the tradeoff between compression density and compression speed
     // (higher = better density but slower).
     //
diff --git a/riegeli/snappy/snappy_reader.h b/riegeli/snappy/snappy_reader.h
index 463c191..b326044 100644
--- a/riegeli/snappy/snappy_reader.h
+++ b/riegeli/snappy/snappy_reader.h
@@ -39,7 +39,13 @@
 // Template parameter independent part of `SnappyReader`.
 class SnappyReaderBase : public ChainReader<Chain> {
  public:
-  class Options {};
+  class Options {
+   public:
+    Options() noexcept {}
+
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+  };
 
   // Returns the compressed `Reader`. Unchanged by `Close()`.
   virtual Reader* SrcReader() const ABSL_ATTRIBUTE_LIFETIME_BOUND = 0;
diff --git a/riegeli/snappy/snappy_writer.h b/riegeli/snappy/snappy_writer.h
index c119ea1..d7a33cb 100644
--- a/riegeli/snappy/snappy_writer.h
+++ b/riegeli/snappy/snappy_writer.h
@@ -51,6 +51,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // Tunes the tradeoff between compression density and compression speed
     // (higher = better density but slower).
     //
diff --git a/riegeli/tensorflow/io/file_reader.h b/riegeli/tensorflow/io/file_reader.h
index f2a13a9..b9f00b8 100644
--- a/riegeli/tensorflow/io/file_reader.h
+++ b/riegeli/tensorflow/io/file_reader.h
@@ -57,6 +57,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // `FileReader` has a larger `kDefaultMaxBufferSize` (1M) because remote
     // file access may have high latency of each operation.
     static constexpr size_t kDefaultMaxBufferSize = size_t{1} << 20;
@@ -251,12 +254,13 @@
   explicit FileReader(Closed) noexcept : FileReaderBase(kClosed) {}
 
   // Will read from the `tsl::RandomAccessFile` provided by `src`.
-  explicit FileReader(Initializer<Src> src, Options options = Options());
+  explicit FileReader(Initializer<Src> src, const Options& options = Options());
 
   // Opens a `tsl::RandomAccessFile` for reading.
   //
   // If opening the file fails, `FileReader` will be failed and closed.
-  explicit FileReader(PathInitializer filename, Options options = Options());
+  explicit FileReader(PathInitializer filename,
+                      const Options& options = Options());
 
   FileReader(FileReader&& that) = default;
   FileReader& operator=(FileReader&& that) = default;
@@ -265,9 +269,9 @@
   // constructing a temporary `FileReader` and moving from it.
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Closed);
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Initializer<Src> src,
-                                          Options options = Options());
+                                          const Options& options = Options());
   ABSL_ATTRIBUTE_REINITIALIZES
-  void Reset(PathInitializer filename, Options options = Options());
+  void Reset(PathInitializer filename, const Options& options = Options());
 
   // Returns the object providing and possibly owning the
   // `tsl::RandomAccessFile` being read from. If the
@@ -287,7 +291,7 @@
 
  private:
   using FileReaderBase::Initialize;
-  void Initialize(PathInitializer filename, Options&& options);
+  void Initialize(PathInitializer filename, const Options& options);
 
   // The object providing and possibly owning the
   // `tsl::RandomAccessFile` being read from.
@@ -296,8 +300,8 @@
 
 explicit FileReader(Closed) -> FileReader<DeleteCtad<Closed>>;
 template <typename Src>
-explicit FileReader(Src&& src,
-                    FileReaderBase::Options options = FileReaderBase::Options())
+explicit FileReader(Src&& src, const FileReaderBase::Options& options =
+                                   FileReaderBase::Options())
     -> FileReader<std::conditional_t<
         std::is_convertible_v<Src&&, PathInitializer>,
         std::unique_ptr<tsl::RandomAccessFile>, TargetT<Src>>>;
@@ -361,7 +365,7 @@
 }
 
 template <typename Src>
-inline FileReader<Src>::FileReader(Initializer<Src> src, Options options)
+inline FileReader<Src>::FileReader(Initializer<Src> src, const Options& options)
     : FileReaderBase(options.buffer_options(), options.env(),
                      options.growing_source()),
       src_(std::move(src)) {
@@ -369,10 +373,11 @@
 }
 
 template <typename Src>
-inline FileReader<Src>::FileReader(PathInitializer filename, Options options)
+inline FileReader<Src>::FileReader(PathInitializer filename,
+                                   const Options& options)
     : FileReaderBase(options.buffer_options(), options.env(),
                      options.growing_source()) {
-  Initialize(std::move(filename), std::move(options));
+  Initialize(std::move(filename), options);
 }
 
 template <typename Src>
@@ -382,7 +387,8 @@
 }
 
 template <typename Src>
-inline void FileReader<Src>::Reset(Initializer<Src> src, Options options) {
+inline void FileReader<Src>::Reset(Initializer<Src> src,
+                                   const Options& options) {
   FileReaderBase::Reset(options.buffer_options(), options.env(),
                         options.growing_source());
   src_.Reset(std::move(src));
@@ -390,15 +396,16 @@
 }
 
 template <typename Src>
-inline void FileReader<Src>::Reset(PathInitializer filename, Options options) {
+inline void FileReader<Src>::Reset(PathInitializer filename,
+                                   const Options& options) {
   FileReaderBase::Reset(options.buffer_options(), options.env(),
                         options.growing_source());
-  Initialize(std::move(filename), std::move(options));
+  Initialize(std::move(filename), options);
 }
 
 template <typename Src>
 inline void FileReader<Src>::Initialize(PathInitializer filename,
-                                        Options&& options) {
+                                        const Options& options) {
   if (ABSL_PREDICT_FALSE(!InitializeFilename(std::move(filename)))) return;
   std::unique_ptr<tsl::RandomAccessFile> src = OpenFile();
   if (ABSL_PREDICT_FALSE(src == nullptr)) return;
diff --git a/riegeli/tensorflow/io/file_writer.h b/riegeli/tensorflow/io/file_writer.h
index 14c31ff..1488ea8 100644
--- a/riegeli/tensorflow/io/file_writer.h
+++ b/riegeli/tensorflow/io/file_writer.h
@@ -60,6 +60,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // `FileWriter` has a larger `kDefaultMaxBufferSize` (1M) because remote
     // file access may have high latency of each operation.
     static constexpr size_t kDefaultMaxBufferSize = size_t{1} << 20;
@@ -199,12 +202,14 @@
   explicit FileWriter(Closed) noexcept : FileWriterBase(kClosed) {}
 
   // Will write to the `tsl::WritableFile` provided by `dest`.
-  explicit FileWriter(Initializer<Dest> dest, Options options = Options());
+  explicit FileWriter(Initializer<Dest> dest,
+                      const Options& options = Options());
 
   // Opens a `tsl::WritableFile` for writing.
   //
   // If opening the file fails, `FileWriter` will be failed and closed.
-  explicit FileWriter(PathInitializer filename, Options options = Options());
+  explicit FileWriter(PathInitializer filename,
+                      const Options& options = Options());
 
   FileWriter(FileWriter&& that) = default;
   FileWriter& operator=(FileWriter&& that) = default;
@@ -213,9 +218,9 @@
   // constructing a temporary `FileWriter` and moving from it.
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Closed);
   ABSL_ATTRIBUTE_REINITIALIZES void Reset(Initializer<Dest> dest,
-                                          Options options = Options());
+                                          const Options& options = Options());
   ABSL_ATTRIBUTE_REINITIALIZES
-  void Reset(PathInitializer filename, Options options = Options());
+  void Reset(PathInitializer filename, const Options& options = Options());
 
   // Returns the object providing and possibly owning the
   // `tsl::WritableFile` being written to. Unchanged by `Close()`.
@@ -233,7 +238,7 @@
 
  private:
   using FileWriterBase::Initialize;
-  void Initialize(PathInitializer filename, Options&& options);
+  void Initialize(PathInitializer filename, const Options& options);
 
   // The object providing and possibly owning the `tsl::WritableFile`
   // being written to.
@@ -242,8 +247,8 @@
 
 explicit FileWriter(Closed) -> FileWriter<DeleteCtad<Closed>>;
 template <typename Dest>
-explicit FileWriter(Dest&& dest,
-                    FileWriterBase::Options options = FileWriterBase::Options())
+explicit FileWriter(Dest&& dest, const FileWriterBase::Options& options =
+                                     FileWriterBase::Options())
     -> FileWriter<
         std::conditional_t<std::is_convertible_v<Dest&&, PathInitializer>,
                            std::unique_ptr<tsl::WritableFile>, TargetT<Dest>>>;
@@ -303,16 +308,18 @@
 }
 
 template <typename Dest>
-inline FileWriter<Dest>::FileWriter(Initializer<Dest> dest, Options options)
+inline FileWriter<Dest>::FileWriter(Initializer<Dest> dest,
+                                    const Options& options)
     : FileWriterBase(options.buffer_options(), options.env()),
       dest_(std::move(dest)) {
   Initialize(dest_.get());
 }
 
 template <typename Dest>
-inline FileWriter<Dest>::FileWriter(PathInitializer filename, Options options)
+inline FileWriter<Dest>::FileWriter(PathInitializer filename,
+                                    const Options& options)
     : FileWriterBase(options.buffer_options(), options.env()) {
-  Initialize(std::move(filename), std::move(options));
+  Initialize(std::move(filename), options);
 }
 
 template <typename Dest>
@@ -322,21 +329,23 @@
 }
 
 template <typename Dest>
-inline void FileWriter<Dest>::Reset(Initializer<Dest> dest, Options options) {
+inline void FileWriter<Dest>::Reset(Initializer<Dest> dest,
+                                    const Options& options) {
   FileWriterBase::Reset(options.buffer_options(), options.env());
   dest_.Reset(std::move(dest));
   Initialize(dest_.get());
 }
 
 template <typename Dest>
-inline void FileWriter<Dest>::Reset(PathInitializer filename, Options options) {
+inline void FileWriter<Dest>::Reset(PathInitializer filename,
+                                    const Options& options) {
   FileWriterBase::Reset(options.buffer_options(), options.env());
-  Initialize(std::move(filename), std::move(options));
+  Initialize(std::move(filename), options);
 }
 
 template <typename Dest>
 inline void FileWriter<Dest>::Initialize(PathInitializer filename,
-                                         Options&& options) {
+                                         const Options& options) {
   if (ABSL_PREDICT_FALSE(!InitializeFilename(std::move(filename)))) return;
   std::unique_ptr<tsl::WritableFile> dest = OpenFile(options.append());
   if (ABSL_PREDICT_FALSE(dest == nullptr)) return;
diff --git a/riegeli/text/ascii_align.h b/riegeli/text/ascii_align.h
index 24eeaca..db4a523 100644
--- a/riegeli/text/ascii_align.h
+++ b/riegeli/text/ascii_align.h
@@ -47,6 +47,9 @@
  public:
   AlignOptions() noexcept {}
 
+  AlignOptions(const AlignOptions& that) = default;
+  AlignOptions& operator=(const AlignOptions& that) = default;
+
   // Options can also be specified by the minimum width alone.
   /*implicit*/ AlignOptions(Position width) : width_(width) {}
 
@@ -85,7 +88,7 @@
  public:
   explicit AsciiLeftType(std::tuple<Initializer<T>...> values,
                          AlignOptions options)
-      : values_(std::move(values)), options_(std::move(options)) {}
+      : values_(std::move(values)), options_(options) {}
 
   template <typename Sink>
   friend void AbslStringify(Sink& dest, const AsciiLeftType& src) {
@@ -175,7 +178,7 @@
 inline AsciiLeftType<TargetRefT<Arg>> AsciiLeft(
     Arg&& arg ABSL_ATTRIBUTE_LIFETIME_BOUND, AlignOptions options) {
   return AsciiLeftType<TargetRefT<Arg>>(
-      std::forward_as_tuple(std::forward<Arg>(arg)), std::move(options));
+      std::forward_as_tuple(std::forward<Arg>(arg)), options);
 }
 
 // `riegeli::OwningAsciiLeft()` is like `riegeli::AsciiLeft()`, but the
@@ -209,7 +212,7 @@
  public:
   explicit AsciiCenterType(std::tuple<Initializer<T>...> values,
                            AlignOptions options)
-      : values_(std::move(values)), options_(std::move(options)) {}
+      : values_(std::move(values)), options_(options) {}
 
   template <typename Sink>
   friend void AbslStringify(Sink& dest, const AsciiCenterType& src) {
@@ -300,7 +303,7 @@
 inline AsciiCenterType<TargetRefT<Arg>> AsciiCenter(
     Arg&& arg ABSL_ATTRIBUTE_LIFETIME_BOUND, AlignOptions options) {
   return AsciiCenterType<TargetRefT<Arg>>(
-      std::forward_as_tuple(std::forward<Arg>(arg)), std::move(options));
+      std::forward_as_tuple(std::forward<Arg>(arg)), options);
 }
 
 // `riegeli::OwningAsciiCenter()` is like `riegeli::AsciiCenter()`, but the
@@ -334,7 +337,7 @@
  public:
   explicit AsciiRightType(std::tuple<Initializer<T>...> values,
                           AlignOptions options)
-      : values_(std::move(values)), options_(std::move(options)) {}
+      : values_(std::move(values)), options_(options) {}
 
   template <typename Sink>
   friend void AbslStringify(Sink& dest, const AsciiRightType& src) {
@@ -424,7 +427,7 @@
 inline AsciiRightType<TargetRefT<Arg>> AsciiRight(
     Arg&& arg ABSL_ATTRIBUTE_LIFETIME_BOUND, AlignOptions options) {
   return AsciiRightType<TargetRefT<Arg>>(
-      std::forward_as_tuple(std::forward<Arg>(arg)), std::move(options));
+      std::forward_as_tuple(std::forward<Arg>(arg)), options);
 }
 
 // `riegeli::OwningAsciiRight()` is like `riegeli::AsciiRight()`, but the
diff --git a/riegeli/xz/xz_reader.h b/riegeli/xz/xz_reader.h
index 990d29e..c5f05b7 100644
--- a/riegeli/xz/xz_reader.h
+++ b/riegeli/xz/xz_reader.h
@@ -53,6 +53,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // What container format to expect.
     //
     // Default: `Container::kXzOrLzma`.
@@ -95,13 +98,13 @@
     //
     // Default: `RecyclingPoolOptions()`.
     Options& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &
+        RecyclingPoolOptions recycling_pool_options) &
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       recycling_pool_options_ = recycling_pool_options;
       return *this;
     }
     Options&& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &&
+        RecyclingPoolOptions recycling_pool_options) &&
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       return std::move(set_recycling_pool_options(recycling_pool_options));
     }
@@ -140,15 +143,15 @@
 
   explicit XzReaderBase(BufferOptions buffer_options, Container container,
                         uint32_t flags,
-                        const RecyclingPoolOptions& recycling_pool_options);
+                        RecyclingPoolOptions recycling_pool_options);
 
   XzReaderBase(XzReaderBase&& that) noexcept;
   XzReaderBase& operator=(XzReaderBase&& that) noexcept;
 
   void Reset(Closed);
   void Reset(BufferOptions buffer_options, Container container, uint32_t flags,
-             const RecyclingPoolOptions& recycling_pool_options);
-  static int GetWindowBits(const Options& options);
+             RecyclingPoolOptions recycling_pool_options);
+  static int GetWindowBits(Options options);
   void Initialize(Reader* src);
   ABSL_ATTRIBUTE_COLD absl::Status AnnotateOverSrc(absl::Status status);
 
@@ -269,9 +272,9 @@
 
 // Implementation details follow.
 
-inline XzReaderBase::XzReaderBase(
-    BufferOptions buffer_options, Container container, uint32_t flags,
-    const RecyclingPoolOptions& recycling_pool_options)
+inline XzReaderBase::XzReaderBase(BufferOptions buffer_options,
+                                  Container container, uint32_t flags,
+                                  RecyclingPoolOptions recycling_pool_options)
     : BufferedReader(buffer_options),
       container_(container),
       flags_(flags),
@@ -307,9 +310,9 @@
   decompressor_.reset();
 }
 
-inline void XzReaderBase::Reset(
-    BufferOptions buffer_options, Container container, uint32_t flags,
-    const RecyclingPoolOptions& recycling_pool_options) {
+inline void XzReaderBase::Reset(BufferOptions buffer_options,
+                                Container container, uint32_t flags,
+                                RecyclingPoolOptions recycling_pool_options) {
   BufferedReader::Reset(buffer_options);
   container_ = container;
   flags_ = flags;
diff --git a/riegeli/xz/xz_writer.h b/riegeli/xz/xz_writer.h
index 019444b..53af298 100644
--- a/riegeli/xz/xz_writer.h
+++ b/riegeli/xz/xz_writer.h
@@ -63,6 +63,9 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
     // What container format to write.
     //
     // `Flush()` is effective and `ReadMode()` is supported only with
@@ -171,13 +174,13 @@
     //
     // Default: `RecyclingPoolOptions()`.
     Options& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &
+        RecyclingPoolOptions recycling_pool_options) &
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       recycling_pool_options_ = recycling_pool_options;
       return *this;
     }
     Options&& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &&
+        RecyclingPoolOptions recycling_pool_options) &&
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       return std::move(set_recycling_pool_options(recycling_pool_options));
     }
@@ -206,14 +209,14 @@
   explicit XzWriterBase(Closed) noexcept : BufferedWriter(kClosed) {}
 
   explicit XzWriterBase(BufferOptions buffer_options, Container container,
-                        const RecyclingPoolOptions& recycling_pool_options);
+                        RecyclingPoolOptions recycling_pool_options);
 
   XzWriterBase(XzWriterBase&& that) noexcept;
   XzWriterBase& operator=(XzWriterBase&& that) noexcept;
 
   void Reset(Closed);
   void Reset(BufferOptions buffer_options, Container container,
-             const RecyclingPoolOptions& recycling_pool_options);
+             RecyclingPoolOptions recycling_pool_options);
   void Initialize(Writer* dest, uint32_t preset, Check check, int parallelism);
   ABSL_ATTRIBUTE_COLD absl::Status AnnotateOverDest(absl::Status status);
 
@@ -331,9 +334,9 @@
 
 // Implementation details follow.
 
-inline XzWriterBase::XzWriterBase(
-    BufferOptions buffer_options, Container container,
-    const RecyclingPoolOptions& recycling_pool_options)
+inline XzWriterBase::XzWriterBase(BufferOptions buffer_options,
+                                  Container container,
+                                  RecyclingPoolOptions recycling_pool_options)
     : BufferedWriter(buffer_options),
       container_(container),
       recycling_pool_options_(recycling_pool_options) {}
@@ -368,9 +371,9 @@
   associated_reader_.Reset();
 }
 
-inline void XzWriterBase::Reset(
-    BufferOptions buffer_options, Container container,
-    const RecyclingPoolOptions& recycling_pool_options) {
+inline void XzWriterBase::Reset(BufferOptions buffer_options,
+                                Container container,
+                                RecyclingPoolOptions recycling_pool_options) {
   BufferedWriter::Reset(buffer_options);
   container_ = container;
   flush_action_ = LZMA_SYNC_FLUSH;
diff --git a/riegeli/zlib/zlib_reader.cc b/riegeli/zlib/zlib_reader.cc
index 1872e8f..c16d1a5 100644
--- a/riegeli/zlib/zlib_reader.cc
+++ b/riegeli/zlib/zlib_reader.cc
@@ -309,7 +309,7 @@
 }
 
 bool RecognizeZlib(Reader& src, ZlibReaderBase::Header header,
-                   const RecyclingPoolOptions& recycling_pool_options) {
+                   RecyclingPoolOptions recycling_pool_options) {
   RIEGELI_ASSERT_NE(header, ZlibReaderBase::Header::kRaw)
       << "Failed precondition of RecognizeZlib(): "
          "Header::kRaw cannot be reliably detected";
diff --git a/riegeli/zlib/zlib_reader.h b/riegeli/zlib/zlib_reader.h
index 2a2e8e5..b85ddca 100644
--- a/riegeli/zlib/zlib_reader.h
+++ b/riegeli/zlib/zlib_reader.h
@@ -54,6 +54,12 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
+    Options(Options&& that) = default;
+    Options& operator=(Options&& that) = default;
+
     // What format of header to expect.
     //
     // Default: `Header::kZlibOrGzip`.
@@ -136,13 +142,13 @@
     //
     // Default: `RecyclingPoolOptions()`.
     Options& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &
+        RecyclingPoolOptions recycling_pool_options) &
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       recycling_pool_options_ = recycling_pool_options;
       return *this;
     }
     Options&& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &&
+        RecyclingPoolOptions recycling_pool_options) &&
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       return std::move(set_recycling_pool_options(recycling_pool_options));
     }
@@ -183,7 +189,7 @@
 
   explicit ZlibReaderBase(BufferOptions buffer_options, int window_bits,
                           bool concatenate, ZlibDictionary&& dictionary,
-                          const RecyclingPoolOptions& recycling_pool_options);
+                          RecyclingPoolOptions recycling_pool_options);
 
   ZlibReaderBase(ZlibReaderBase&& that) noexcept;
   ZlibReaderBase& operator=(ZlibReaderBase&& that) noexcept;
@@ -191,7 +197,7 @@
   void Reset(Closed);
   void Reset(BufferOptions buffer_options, int window_bits, bool concatenate,
              ZlibDictionary&& dictionary,
-             const RecyclingPoolOptions& recycling_pool_options);
+             RecyclingPoolOptions recycling_pool_options);
   static int GetWindowBits(const Options& options);
   void Initialize(Reader* src);
   ABSL_ATTRIBUTE_COLD absl::Status AnnotateOverSrc(absl::Status status);
@@ -207,7 +213,7 @@
  private:
   // For `ZStreamDeleter`.
   friend bool RecognizeZlib(Reader& src, ZlibReaderBase::Header header,
-                            const RecyclingPoolOptions& recycling_pool_options);
+                            RecyclingPoolOptions recycling_pool_options);
 
   struct ZStreamDeleter {
     // `void*` is `z_stream*`. Avoid including `zlib.h` in the header.
@@ -305,10 +311,8 @@
 bool RecognizeZlib(
     Reader& src,
     ZlibReaderBase::Header header = ZlibReaderBase::Header::kZlibOrGzip,
-    const RecyclingPoolOptions& recycling_pool_options =
-        RecyclingPoolOptions());
-bool RecognizeZlib(Reader& src,
-                   const RecyclingPoolOptions& recycling_pool_options);
+    RecyclingPoolOptions recycling_pool_options = RecyclingPoolOptions());
+bool RecognizeZlib(Reader& src, RecyclingPoolOptions recycling_pool_options);
 
 // Returns the claimed uncompressed size of Gzip-compressed data (with
 // `ZlibWriterBase::Header::kGzip`) modulo 4G. The compressed stream must not
@@ -330,8 +334,7 @@
 
 inline ZlibReaderBase::ZlibReaderBase(
     BufferOptions buffer_options, int window_bits, bool concatenate,
-    ZlibDictionary&& dictionary,
-    const RecyclingPoolOptions& recycling_pool_options)
+    ZlibDictionary&& dictionary, RecyclingPoolOptions recycling_pool_options)
     : BufferedReader(buffer_options),
       window_bits_(window_bits),
       concatenate_(concatenate),
@@ -376,10 +379,9 @@
   dictionary_ = ZlibDictionary();
 }
 
-inline void ZlibReaderBase::Reset(
-    BufferOptions buffer_options, int window_bits, bool concatenate,
-    ZlibDictionary&& dictionary,
-    const RecyclingPoolOptions& recycling_pool_options) {
+inline void ZlibReaderBase::Reset(BufferOptions buffer_options, int window_bits,
+                                  bool concatenate, ZlibDictionary&& dictionary,
+                                  RecyclingPoolOptions recycling_pool_options) {
   BufferedReader::Reset(buffer_options);
   window_bits_ = window_bits;
   concatenate_ = concatenate;
@@ -445,7 +447,7 @@
 }
 
 inline bool RecognizeZlib(Reader& src,
-                          const RecyclingPoolOptions& recycling_pool_options) {
+                          RecyclingPoolOptions recycling_pool_options) {
   return RecognizeZlib(src, ZlibReaderBase::Header::kZlibOrGzip,
                        recycling_pool_options);
 }
diff --git a/riegeli/zlib/zlib_writer.h b/riegeli/zlib/zlib_writer.h
index 2baf84e..ebfa756 100644
--- a/riegeli/zlib/zlib_writer.h
+++ b/riegeli/zlib/zlib_writer.h
@@ -53,6 +53,12 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
+    Options(Options&& that) = default;
+    Options& operator=(Options&& that) = default;
+
     // What format of header to write.
     //
     // Default: `Header::kZlib`.
@@ -145,13 +151,13 @@
     //
     // Default: `RecyclingPoolOptions()`.
     Options& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &
+        RecyclingPoolOptions recycling_pool_options) &
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       recycling_pool_options_ = recycling_pool_options;
       return *this;
     }
     Options&& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &&
+        RecyclingPoolOptions recycling_pool_options) &&
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       return std::move(set_recycling_pool_options(recycling_pool_options));
     }
@@ -178,7 +184,7 @@
 
   explicit ZlibWriterBase(BufferOptions buffer_options, int window_bits,
                           ZlibDictionary&& dictionary,
-                          const RecyclingPoolOptions& recycling_pool_options);
+                          RecyclingPoolOptions recycling_pool_options);
 
   ZlibWriterBase(ZlibWriterBase&& that) noexcept;
   ZlibWriterBase& operator=(ZlibWriterBase&& that) noexcept;
@@ -186,7 +192,7 @@
   void Reset(Closed);
   void Reset(BufferOptions buffer_options, int window_bits,
              ZlibDictionary&& dictionary,
-             const RecyclingPoolOptions& recycling_pool_options);
+             RecyclingPoolOptions recycling_pool_options);
   static int GetWindowBits(const Options& options);
   void Initialize(Writer* dest, int compression_level);
   ABSL_ATTRIBUTE_COLD absl::Status AnnotateOverDest(absl::Status status);
@@ -300,7 +306,7 @@
 
 inline ZlibWriterBase::ZlibWriterBase(
     BufferOptions buffer_options, int window_bits, ZlibDictionary&& dictionary,
-    const RecyclingPoolOptions& recycling_pool_options)
+    RecyclingPoolOptions recycling_pool_options)
     : BufferedWriter(buffer_options),
       window_bits_(window_bits),
       dictionary_(std::move(dictionary)),
@@ -338,9 +344,9 @@
   associated_reader_.Reset();
 }
 
-inline void ZlibWriterBase::Reset(
-    BufferOptions buffer_options, int window_bits, ZlibDictionary&& dictionary,
-    const RecyclingPoolOptions& recycling_pool_options) {
+inline void ZlibWriterBase::Reset(BufferOptions buffer_options, int window_bits,
+                                  ZlibDictionary&& dictionary,
+                                  RecyclingPoolOptions recycling_pool_options) {
   BufferedWriter::Reset(buffer_options);
   window_bits_ = window_bits;
   recycling_pool_options_ = recycling_pool_options;
diff --git a/riegeli/zstd/zstd_reader.h b/riegeli/zstd/zstd_reader.h
index d11f32d..fb62205 100644
--- a/riegeli/zstd/zstd_reader.h
+++ b/riegeli/zstd/zstd_reader.h
@@ -46,6 +46,12 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
+    Options(Options&& that) = default;
+    Options& operator=(Options&& that) = default;
+
     // If `true`, supports decompressing as much as possible from a truncated
     // source, then retrying when the source has grown. This has a small
     // performance penalty.
@@ -107,13 +113,13 @@
     //
     // Default: `RecyclingPoolOptions()`.
     Options& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &
+        RecyclingPoolOptions recycling_pool_options) &
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       recycling_pool_options_ = recycling_pool_options;
       return *this;
     }
     Options&& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &&
+        RecyclingPoolOptions recycling_pool_options) &&
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       return std::move(set_recycling_pool_options(recycling_pool_options));
     }
@@ -153,7 +159,7 @@
 
   explicit ZstdReaderBase(BufferOptions buffer_options, bool growing_source,
                           bool concatenate, ZstdDictionary&& dictionary,
-                          const RecyclingPoolOptions& recycling_pool_options);
+                          RecyclingPoolOptions recycling_pool_options);
 
   ZstdReaderBase(ZstdReaderBase&& that) noexcept;
   ZstdReaderBase& operator=(ZstdReaderBase&& that) noexcept;
@@ -161,7 +167,7 @@
   void Reset(Closed);
   void Reset(BufferOptions buffer_options, bool growing_source,
              bool concatenate, ZstdDictionary&& dictionary,
-             const RecyclingPoolOptions& recycling_pool_options);
+             RecyclingPoolOptions recycling_pool_options);
   void Initialize(Reader* src);
   ABSL_ATTRIBUTE_COLD absl::Status AnnotateOverSrc(absl::Status status);
 
@@ -283,8 +289,7 @@
 
 inline ZstdReaderBase::ZstdReaderBase(
     BufferOptions buffer_options, bool growing_source, bool concatenate,
-    ZstdDictionary&& dictionary,
-    const RecyclingPoolOptions& recycling_pool_options)
+    ZstdDictionary&& dictionary, RecyclingPoolOptions recycling_pool_options)
     : BufferedReader(buffer_options),
       growing_source_(growing_source),
       concatenate_(concatenate),
@@ -328,10 +333,10 @@
   dictionary_ = ZstdDictionary();
 }
 
-inline void ZstdReaderBase::Reset(
-    BufferOptions buffer_options, bool growing_source, bool concatenate,
-    ZstdDictionary&& dictionary,
-    const RecyclingPoolOptions& recycling_pool_options) {
+inline void ZstdReaderBase::Reset(BufferOptions buffer_options,
+                                  bool growing_source, bool concatenate,
+                                  ZstdDictionary&& dictionary,
+                                  RecyclingPoolOptions recycling_pool_options) {
   BufferedReader::Reset(buffer_options);
   growing_source_ = growing_source;
   concatenate_ = concatenate;
diff --git a/riegeli/zstd/zstd_writer.h b/riegeli/zstd/zstd_writer.h
index ef2b3c8..84d0ab7 100644
--- a/riegeli/zstd/zstd_writer.h
+++ b/riegeli/zstd/zstd_writer.h
@@ -50,6 +50,12 @@
    public:
     Options() noexcept {}
 
+    Options(const Options& that) = default;
+    Options& operator=(const Options& that) = default;
+
+    Options(Options&& that) = default;
+    Options& operator=(Options&& that) = default;
+
     // Tunes the tradeoff between compression density and compression speed
     // (higher = better density but slower).
     //
@@ -250,13 +256,13 @@
     //
     // Default: `RecyclingPoolOptions()`.
     Options& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &
+        RecyclingPoolOptions recycling_pool_options) &
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       recycling_pool_options_ = recycling_pool_options;
       return *this;
     }
     Options&& set_recycling_pool_options(
-        const RecyclingPoolOptions& recycling_pool_options) &&
+        RecyclingPoolOptions recycling_pool_options) &&
         ABSL_ATTRIBUTE_LIFETIME_BOUND {
       return std::move(set_recycling_pool_options(recycling_pool_options));
     }
@@ -288,7 +294,7 @@
                           ZstdDictionary&& dictionary,
                           std::optional<Position> pledged_size,
                           bool reserve_max_size,
-                          const RecyclingPoolOptions& recycling_pool_options);
+                          RecyclingPoolOptions recycling_pool_options);
 
   ZstdWriterBase(ZstdWriterBase&& that) noexcept;
   ZstdWriterBase& operator=(ZstdWriterBase&& that) noexcept;
@@ -296,7 +302,7 @@
   void Reset(Closed);
   void Reset(BufferOptions buffer_options, ZstdDictionary&& dictionary,
              std::optional<Position> pledged_size, bool reserve_max_size,
-             const RecyclingPoolOptions& recycling_pool_options);
+             RecyclingPoolOptions recycling_pool_options);
   void Initialize(Writer* dest, int compression_level, int window_log_or_0,
                   int target_cblock_size_or_0, bool store_checksum);
   ABSL_ATTRIBUTE_COLD absl::Status AnnotateOverDest(absl::Status status);
@@ -394,7 +400,7 @@
 inline ZstdWriterBase::ZstdWriterBase(
     BufferOptions buffer_options, ZstdDictionary&& dictionary,
     std::optional<Position> pledged_size, bool reserve_max_size,
-    const RecyclingPoolOptions& recycling_pool_options)
+    RecyclingPoolOptions recycling_pool_options)
     : BufferedWriter(buffer_options),
       dictionary_(std::move(dictionary)),
       pledged_size_(pledged_size),
@@ -439,10 +445,11 @@
   associated_reader_.Reset();
 }
 
-inline void ZstdWriterBase::Reset(
-    BufferOptions buffer_options, ZstdDictionary&& dictionary,
-    std::optional<Position> pledged_size, bool reserve_max_size,
-    const RecyclingPoolOptions& recycling_pool_options) {
+inline void ZstdWriterBase::Reset(BufferOptions buffer_options,
+                                  ZstdDictionary&& dictionary,
+                                  std::optional<Position> pledged_size,
+                                  bool reserve_max_size,
+                                  RecyclingPoolOptions recycling_pool_options) {
   BufferedWriter::Reset(buffer_options);
   dictionary_ = std::move(dictionary);
   pledged_size_ = pledged_size;