home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c++.moderated      Moderated discussion of C++ superhackery      33,346 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 33,012 of 33,346   
   Jeff Flinn to Jonathan Thornburg   
   Re: want to pass vector to fn expe   
   01 May 13 09:12:56   
   
   From: TriumphSprint2000@this.is.invalid   
      
   { Please limit your quoting to the minimum needed to establish context   
   -mod }   
      
   On 4/18/2013 11:45 PM, Jonathan Thornburg wrote:   
   > Consider the following toy program:   
   >   
   > [Disclaimer: This is an abstraction of a design problem I currently face   
   > in "real" code.  This is not a homework assignment.]   
   >   
   >   
   > --- begin sample code ---   
   > // investigate passing vector to a function expecting   
   vector   
   >   
   > #include    
   > #include    
   > #include    
   > using std::cout;   
   >   
   > class	interval   
   > 	{   
   > public:   
   > 	int min() const { return min_; }   
   > 	int max() const { return max_; }   
   > 	void make_empty() { min_ = 0; max_ = -1; }   
   > 	interval(int min_in, int max_in)   
   > 		: min_(min_in), max_(max_in)   
   > 		{ /* empty constructor body */ }   
   > 	// default compiler-generated destructor is ok   
   > 	// default compiler-generated copy ctor & assignment op are ok   
   > private:   
   > 	int min_, max_;   
   > 	};   
   >   
   > // prototype   
   > void print_vector_of_intervals(const std::vector& vci);   
   >   
   > int main()   
   > {   
   > std::vector vi;   
   > vi.push_back(new interval(2,3));   
   > vi.push_back(new interval(5,7));   
   > vi.push_back(new interval(11,13));   
   >   
   > print_vector_of_intervals(vi);   
   > }   
   >   
   > // print each interval pointed-to by a member of  vci   
   > // n.b. this function promises not to change the vector-of-pointers   
   > //      AND not to change the pointed-to intervals   
   > void print_vector_of_intervals(const std::vector& vci)   
   > {   
   > 	for (int i = 0 ; i < static_cast(vci.size()) ; ++i)   
   > 	{   
   > 	const interval* pI = vci.at(i);   
   > 	assert(pI != NULL);   
   > 	const interval& I = *pI;   
   > 	cout << "interval " << i << " = "   
   > 	     << "[" << I.min() << ", " << I.max() << "]" << "\n";   
   > 	}   
   > }   
   > --- end sample code ---   
   >   
   > As written, the program is accepted without complaint by g++ 4.6.2 and   
   > clang++ 3.0 (both with -W -Wall), and produces the expected output when   
   > run.   
   >   
   > However, as written there's a design weakness in the program:   
   > print_vector_of_intervals() promises in its header comment not to change   
   > the pointed-to intervals, but its prototype doesn't reflect that promise.   
   > So, the "obvious" solution is to uncomment the commented-out "const" in   
   > print_vector_of_intervals()'s prototype and its declaration, so that the   
   > prototype looks like this:   
   >   
   > void print_vector_of_intervals(const std::vector& vci);   
   >   
   > Now the prototype makes explicit the semantics which were previous only   
   > described in the comments, namely that  print_vector_of_intervals() won't   
   > modify the pointed-to intervals.  (More precisely, that it won't call any   
   > non-const interval:: member functions (such as interval::make_empty())   
   > on the pointed-to intervals.)   
   >   
   > Alas, now main isn't allowed to pass a  std::vector  to   
   > print_vector_of_intervals():  Both g++ and clang++ agree that the   
   modified   
   > code is invalid, because there's no known conversion from   
   >    std::vector   
   > to   
   >    std::vector   
   >   
   >   
   > My basic question is, what to do about this?  That is, what design(s)   
   > can/should be used (in any/all of C++98, 03, or 11) so that client code   
   > which has a  std::vector  can pass (a reference to) that   
   vector   
   > to a function which promises not to change either the vector-of-pointers   
   > or the pointed-to objects?   
   >   
   > I can think of two obvious solutions... each with fairly obvious   
   drawbacks:   
   > (a) omit the "const" in the prototype & declaration of   
   >      print_vector_of_intervals()   
   > (b) have client code copy the pointers to a temporary   
   >      vector-of-pointers-to-const-intervals, and then call   
   >      print_vector_of_intervals()  on that temporary   
   >   
   > Is there an elegant solution that I've overlooked?   
   >   
   > [Of course for this toy program, it's easy to just have a vector of   
   > intervals rather than a vector of pointers-to-intervals, but in my   
   > "real" code the objects in question are large and noncopyable, so   
   > vector-of-pointers is the appropriate data structure.]   
      
   Along the lines of Chris' posting, making Interval output streamable you   
   can use boost range as below:   
      
   #include    
   #include    
   #include    
      
   std::ostream& operator<<(std::ostream& os, Interval const& i)   
   {   
         os << "interval " << " = [" << i.min() << ", " << i.max() << "]";   
   }   
      
   struct is_not_null_ptr   
   {   
        template bool operator()( T t ) const { return !!t; }   
   };   
      
   using namespace boost::adaptors;   
   using namespace boost;   
      
   copy( v | filtered(is_not_null()) | indirected   
         , std::ostream_iterator(std::cout, "\n"));   
      
   This separates out streaming from the filtering and deref'ing. The   
   streaming operator promises not to modify the interval. std::copy, which   
   boost::range::copy emulates is a non-modifying algorithm.   
      
   IMO a better approach is encapsulate the std::vector rather   
   than trying to convert to std::vector, thus ensuring   
   valid invariants. For example the filtered(is_not_null()) would not be   
   needed if your class invariant was for all i in v i != 0.   
      
   Jeff   
      
      
   --   
         [ See http://www.gotw.ca/resources/clcm.htm for info about ]   
         [ comp.lang.c++.moderated.    First time posters: Do this! ]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca