lmi-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi-commits] [lmi] master b518132 4/4: Remove the latent defect just ad


From: Greg Chicares
Subject: [lmi-commits] [lmi] master b518132 4/4: Remove the latent defect just added
Date: Wed, 5 Sep 2018 20:56:27 -0400 (EDT)

branch: master
commit b518132022d0dab59226f584778973265b71e532
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>

    Remove the latent defect just added
    
    See the two immediately preceding commits.
    
    Abnormal termination is a grave defect, which this commit removes by
    asserting the validity of ctor arguments at the proper moment. To see
    why this option seems better than any other, consider the tradeoffs:
    
     - Constness could be forsaken.
    
     - Constness could be subverted with const_cast.
    
    Or assertions could be made at the proper time by alternative means:
    
     - Push them into a base class, complexifying the design.
    
     - The comma operator won't help, but the conditional operator could
       be used in the ctor-initializer, e.g.:
         ,rows_per_group_ {0 < rows_per_group ? rows_per_group : throw 0;}
       which is less readable than this commit.
    
     - Templates. SFINAE. A barrier to comprehension: overkill here.
    
     - The assertions could be expressed in an macro. Not.
    
     - The possibility of abnormal termination could be disregarded,
       because how could that go wrong?
    
    Join these two lines to produce one URL:
      https://isocpp.org/wiki/faq/ctors
      #initializing-members-from-other-members
    for a discussion of the morality of this commit, which warns of "subtle
    order-dependency errors if someone reorganizes the layout of member
    objects". Yet these calculations are manifestly order-dependent, and
    rearranging the lines of code in the antepenultimate commit would have
    the same effect as rearranging the mem-initializers here. The
    precondition-assertion function could be rewritten to reference the ctor
    arguments directly, e.g.:
       foo::foo(int a, int b)
       :ctor_args_are_sane_ {assert_preconditions(a, b)}
       ,[all other mem-initializers]
    which would arguably alleviate the member-object order dependency, but
    at the cost of creating a dependency on the order of those arguments:
       :ctor_args_are_sane_ {assert_preconditions(b, a)} // Oops!
    while also introducing obscurity and maintenance overhead.
---
 report_table.cpp      | 13 +++++++++----
 report_table.hpp      |  4 ++++
 report_table_test.cpp |  2 --
 3 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/report_table.cpp b/report_table.cpp
index 5a55979..a1864a9 100644
--- a/report_table.cpp
+++ b/report_table.cpp
@@ -175,12 +175,19 @@ std::vector<int> set_column_widths
     return w;
 }
 
-/// Preconditions: 0 <= total_rows && 0 < rows_per_group <= max_lines_per_page
+bool paginator::assert_preconditions() const
+{
+    LMI_ASSERT(0 <= total_rows_);
+    LMI_ASSERT(0 <  rows_per_group_                       );
+    LMI_ASSERT(     rows_per_group_ <= max_lines_per_page_);
+    return true;
+}
 
 paginator::paginator(int total_rows, int rows_per_group, int 
max_lines_per_page)
     :total_rows_         {total_rows}
     ,rows_per_group_     {rows_per_group}
     ,max_lines_per_page_ {max_lines_per_page}
+    ,ctor_args_are_sane_ {assert_preconditions()}
     // "+ 1": blank-line separator after each group.
     ,lines_per_group_    {rows_per_group_ + 1}
     // "+ 1": no blank-line separator after the last group.
@@ -188,9 +195,7 @@ paginator::paginator(int total_rows, int rows_per_group, 
int max_lines_per_page)
     ,rows_per_page_      {rows_per_group_ * groups_per_page_}
     ,page_count_         {1}
 {
-    LMI_ASSERT(0 <= total_rows_);
-    LMI_ASSERT(0 <  rows_per_group_                       );
-    LMI_ASSERT(     rows_per_group_ <= max_lines_per_page_);
+    // Preconditions: see assert_preconditions().
 
     // If there are zero rows of data, then one empty page is wanted.
     if(0 == total_rows_)
diff --git a/report_table.hpp b/report_table.hpp
index b548cf2..930f0f4 100644
--- a/report_table.hpp
+++ b/report_table.hpp
@@ -142,11 +142,15 @@ class LMI_SO paginator
     int page_count() const {return page_count_;}
 
   private:
+    bool assert_preconditions() const;
+
     // Ctor arguments.
     int const total_rows_;
     int const rows_per_group_;
     int const max_lines_per_page_;
 
+    bool const ctor_args_are_sane_ {false};
+
     // Internals in dependency order.
     int const lines_per_group_;
     int const groups_per_page_;
diff --git a/report_table_test.cpp b/report_table_test.cpp
index 68f7e7e..c8e3a1d 100644
--- a/report_table_test.cpp
+++ b/report_table_test.cpp
@@ -440,13 +440,11 @@ void report_table_test::test_paginator()
         );
 
     // Negative number of rows per group.
-#if 0
     BOOST_TEST_THROW
         (paginator(1, -1, 1)
         ,std::runtime_error
         ,lmi_test::what_regex("^Assertion.*failed")
         );
-#endif // 0
 
     // Insufficient room to print even one group.
     BOOST_TEST_THROW



reply via email to

[Prev in Thread] Current Thread [Next in Thread]