title: Constructors and Advanced Exception Throwing C++
body: <p>I have to analyze this C++ code which involves exceptions, but I’m not used to analyzing what code is supposed to do. There’s several things about it I don’t understand. Additionally, I don’t have experience with a buffer data structure or advanced details of throwing exceptions in C++.</p>
  
  <p>What is the max size of the data structure?</p>
  
  <ul>
  <li>That is to say, if a Seq_Buffer is made with size_ = 100, how many
  elements can be stored?</li>
  <li>My intuition tells me that if you create    something with size 100,
  it’s max size will be 100, but I can’t be    sure with facts.</li>
  </ul>
  
  <p>Constructors can throw exceptions in c++?</p>
  
  <ul>
  <li>Can the constructor for Seq_Buffer throw an exception? </li>
  <li>Assuming this is true, why does that work without explicating
  stating a try, catch, or throw block? I thought that was the only way to get exceptions</li>
  </ul>
  
  <p>I’ve tried searching for these two questions, but I’m really quite lost. Thank you for taking the time to read.I’ve tried searching for these two questions, but I’m really quite lost. Thank you for taking the time to read.</p>
  
  <p>The code for the Seq_Buffer class with its constructor is below:</p>
  
  <pre><code>#ifndef SEQBUFFER_H
  #define SEQBUFFER_H
  
  #include &lt;memory&gt;
  #include &lt;experimental/optional&gt;
  
  #include "optional.h"
  
  // Exceptions classes
  struct full_buffer {};
  struct empty_buffer {};
  
  // Sequential buffer for values of type T
  template &lt;typename T&gt;
  class seq_buffer {
  public:
    // Constructs a buffer for n elements
    seq_buffer(int n) :
      size_{n},
      buf_{new item_type[size_]}
    {
    }
  
    // Default destructor
    ~seq_buffer() = default;
  
    // Size of buffer
    int size() const noexcept { 
      return size_; 
    }
  
    // Is buffer empty?
    bool empty() const noexcept { 
      return next_read_ == next_write_; 
    }
  
    // Is buffer full?
    bool full() const noexcept {
      const int next = next_position(next_write_);
      return next == next_read_;
    }
  
    // Put element x into buffer with marker last.
    // An empty element signals end of buffer.
    void put(const optional&lt;T&gt; &amp; x);
  
    // Gets a pair with next element and last indication.
    // Pair is accessed through members first and second
    optional&lt;T&gt; get();
  
  private:
    // Compute next position after p following circular order
    int next_position(int p) const noexcept {
      return p + ((p+1&gt;=size_)?(1-size_):1);
    }
  
  private:
    // Size of buffer
    const int size_;
  
    using item_type = optional&lt;T&gt;;
  
    // Unique pointer to buffer of size_ elements.
    std::unique_ptr&lt;item_type[]&gt; buf_;
  
    // Next position to read
    int next_read_ = 0;
  
    // Next position to write
    int next_write_ = 0;
  };
  
  template &lt;typename T&gt;
  void seq_buffer&lt;T&gt;::put(const optional&lt;T&gt; &amp; x)
  {
    const int next = next_position(next_write_);
    if (next == next_read_) throw full_buffer{};
    if (!x) {
      buf_[next_write_] = {};
    }
    else {
      buf_[next_write_] = *x;
    }
    next_write_ = next;
  }
  
  template &lt;typename T&gt;
  optional&lt;T&gt; seq_buffer&lt;T&gt;::get()
  {
    if (empty()) throw empty_buffer{};
    auto res = buf_[next_read_];
    next_read_ = next_position(next_read_);
    return res;
  }
  
  #endif
  </code></pre>