Thread: WTF con't

  1. #1
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300

    WTF con't

    Wow, kinda boggled by my first C++ program:
    Code:
    #include <iostream>
    #include <string>
    using namespace std;
    
    class nlist : public string {
    	public:
    		nlist(string in) {
    			assign(in);
    		}
    		int extract(size_t *pos) {
    			int retv = 0, m = 1;
    			size_t end, place;
    			while (at(*pos) < '0'|| at(*pos) > '9') {
    //				printf("%d %d\n",*pos,at(*pos)); fflush(stdout);
    				(*pos)++;
    			}
    			end = *pos;
    			while (at(end) > '0'&& at(end) < '9') end++;
    			place = end;
    			end--;
    			while (end>=*pos) {
    				if (end<0) break;
    	printf("pos %d end %d\n",*pos, end); fflush(stdout);
    				retv += (at(end--)-48)*m;
    				m*=10;
    			}
    			*pos = place;
    			return retv;
    		}
    };
    
    int main() {
    	string src="1,44,56,33\n";
    	nlist nums(src);
    	size_t len = nums.size(), pos = 0;
    
    	cout << nums;
    	while (pos<len) cout << nums.extract(&pos);
    
    	return 0;
    }
    Considering the conditions in red, how is it possible that I get this at runtime:

    1,44,56,33
    pos 0 end 0
    pos 0 end -1
    terminate called after throwing an instance of 'std:ut_of_range'
    what(): basic_string::at
    Aborted


    "If (end<0) break;" then it proceeds to the next line and reports end = -1.
    ???????????????
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Maybe the problem lies here, considering that there is no bounds checking other than the use of at():
    Code:
    while (at(*pos) < '0'|| at(*pos) > '9') {
        (*pos)++;
    }
    Again, please stop publicly inheriting from std::string. I know that inheritance is a novelty for you right now, but it is better that you do not start developing bad habits.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Your first C++ program? Really? With the comparison statements you've made before?

    First of all, size_t is unsigned, hence the name (negative size?).

    Second what laserlight said, don't inherit std::string (or most of the standard implementation besides streams and such for that matter).
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  4. #4
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by laserlight View Post
    Maybe the problem lies here, considering that there is no bounds checking other than the use of at():
    Nope. It's because end is -1:
    Code:
    			while (end>=*pos) {
    				if (end<0) break;
    	printf("pos %d end %d\n",*pos, end); fflush(stdout);    
    Again, the output:
    pos 0 end 0
    pos 0 end -1

    I do not understand how a loop which has that condition and that break would continue iterating. It should not be possible for that printf to execute while end < 0.

    Okay, I guessing it's because size_t is an unsigned type....

    Vis, deriving from std::string, yes, I understand this not a wise design move, I'm not planning on using it for anything except getting a feel for the syntax.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  5. #5
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by MK27 View Post
    Okay, I guessing it's because size_t is an unsigned type....
    Yep. Man, this C++ is weird.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by MK27
    Man, this C++ is weird.
    size_t is inherited from C.

    This is how I might implement the algorithm you have in mind with the kind of usage that you have in mind:
    Code:
    #include <iostream>
    #include <string>
    
    /* Extracts next integer in str starting from pos and assigns it to result.
     * Returns the position of the first unprocessed character or std::string::npos
     * if there there are no more integers left to process.
     */
    std::string::size_type
    extract(const std::string& str, std::string::size_type pos, int& result);
    
    int main()
    {
        std::string::size_type pos = 0;
        int num;
        while ((pos = extract("1,44,56,33\n", pos, num)) != std::string::npos)
        {
            std::cout << num << '\n';
        }
        std::cout.flush();
    }
    
    std::string::size_type
    extract(const std::string& str, std::string::size_type pos, int& result)
    {
        const std::string::size_type size = str.size();
    
        // Skip non-digit characters.
        for (; pos < size && (str[pos] < '0' || str[pos] > '9'); ++pos)
        {
            // Nothing to do here.
        }
    
        // Find last character of integer to be extracted.
        std::string::size_type end_pos = pos;
        for (; end_pos < size && (str[end_pos] >= '0' && str[end_pos] <= '9'); ++end_pos)
        {
            // Nothing to do here.
        }
    
        if (pos < end_pos)
        {
            // Extract integer portion into an int.
            result = 0;
            int multiplier = 1;
            for (std::string::size_type i = end_pos; i > pos;)
            {
                result += multiplier * (str[--i] - '0');
                multiplier *= 10;
            }
            return end_pos;
        }
        else
        {
            // Integer not found.
            return std::string::npos;
        }
    }
    That said, I realised that if we do not follow your algorithm so exactly, we can simplify, e.g.,
    Code:
    std::string::size_type
    extract(const std::string& str, std::string::size_type pos, int& result)
    {
        static const char* const digits = "0123456789";
    
        pos = str.find_first_of(digits, pos);
    
        if (pos == std::string::npos)
        {
            return std::string::npos; // Integer not found.
        }
    
        // Find one past the last character of non-negative integer to be extracted.
        std::string::size_type end_pos = str.find_first_not_of(digits, pos);
        if (end_pos == std::string::npos)
        {
            end_pos = str.size();
        }
    
        // Extract non-negative integer value into an int.
        result = 0;
        int multiplier = 1;
        for (std::string::size_type i = end_pos; i > pos;)
        {
            result += multiplier * (str[--i] - '0');
            multiplier *= 10;
        }
        return end_pos;
    }
    Last edited by laserlight; 02-22-2010 at 04:08 PM. Reason: While loops are probably better than for loops with empty bodies.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    I guess I have to get on reading that book. Quick question(s):

    1) so std::string::size_type is implementation specific, or always size_t?

    Anyway thanks for that. I actually didn't scroll down far enough to notice stuff like "find_first_not_of". std::string, pretty neat.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by MK27
    1) so std::string::size_type is implementation specific, or always size_t?
    std::string is a typedef for std::basic_string<char>, which has a default third template argument of std::allocator<char>. Now, the size_type member for std::basic_string is a typedef for the size_type member of this allocator. Since std::allocator<char>::size_type is a typedef for std::size_t, std::string::size_type is thus an alias for std::size_t.

    Quote Originally Posted by MK27
    I actually didn't scroll down far enough to notice stuff like "find_first_not_of". std::string, pretty neat.
    Yeah, though it is a little less efficient than checking than comparing with '0' and '9'. A generic algorithm with a predicate could be used to get around that, but then writing a predicate currently often requires more boilerplate than is desirable, at least without the use of say Boost.Lamdba and such.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Yeah, though it is a little less [...] of say Boost.Lamdba and such.
    You could also go the other direction.

    Still a lot of work. (NNR)

    Soma

    Code:
    #include <algorithm>
    #include <iostream>
    #include <iterator>
    #include <sstream>
    #include <string>
    #include <vector>
    
    // a sortof `meta-function' to provide a default delmiter value
    // based on the types used in the operation and
    // the specializations needed for the standard streams
    
    template
    <
    	typename T
    >
    struct delimiter
    {
    	static T get();
    };
    
    template <> struct delimiter<char>
    {
    	static char get()
    	{
    		return(',');
    	}
    };
    
    template <> struct delimiter<wchar_t>
    {
    	static wchar_t get()
    	{
    		return(L',');
    	}
    };
    
    // a `meta-function' to work around a few broken compilers
    // and a few problematic `iterator_traits' implementation
    // issues so we can properly determine the type to be
    // stored
    
    // works because the nested `value_type' of
    // unspecialized `std::iterator_traits' should
    // always be `void'
    
    template
    <
    	typename itT,
    	typename typeT
    >
    struct discover_nested_type2
    {
    	typedef typeT type;
    };
    
    template
    <
    	typename itT
    >
    struct discover_nested_type2<itT, void>
    {
    	typedef typename itT::container_type::value_type type;
    };
    
    // the interface to the above `meta-function'
    
    template
    <
    	typename itT
    >
    struct discover_nested_type
    {
    	typedef typename std::iterator_traits<itT>::value_type maybe_value_type;
    	typedef typename discover_nested_type2<itT, maybe_value_type>::type type;
    };
    
    // a function to "parse" delimted strings
    // ignores quoted values and quoted value pairs
    
    template
    <
    	typename inputT,
    	typename outputT
    >
    void process
    (
    	inputT begin, // expects a `char *',
    	inputT end,   // `wchar_t *', or compatible
    	outputT out,  // expects an "input iterator" of some kind (including trivial pointer types)
    	typename std::iterator_traits<inputT>::value_type delim = delimiter<typename std::iterator_traits<inputT>::value_type>::get()
    )
    {
    	using namespace std;
    	typedef typename iterator_traits<inputT>::value_type char_type;
    	typedef typename discover_nested_type<outputT>::type value_type;
    	basic_string<char_type> temp(begin, end);
    	basic_istringstream<char_type> input(temp);
    	while(getline(input, temp, delim))
    	{
    		value_type data;
    		basic_istringstream<char_type> tin(temp);
    		if(tin >> data)
    		{
    			*out++ = data;
    		}
    		else
    		{
    			throw("something");
    		}
    	}
    }
    
    int main()
    {
    	using namespace std;
    	string test1("1.1,2.2,3.3,4.4");
    	vector<double> data1;
    	process(test1.begin(), test1.end(), back_inserter(data1));
    	cout << "number of elements (1): " << data1.size() << '\n';
    	copy(data1.begin(), data1.end(), ostream_iterator<double>(cout, "\n"));
    	char test2[] = "-5&6&-7&8&9";
    	int sizeof_test2(sizeof(test2)/sizeof(test2[0]));
    	int data2[5];
    	int sizeof_data2(sizeof(data2)/sizeof(data2[0]));
    	process(test2, test2 + sizeof_test2, data2, '&');
    	cout << "\nnumber of elements (2): " << 5 << '\n';
    	copy(data2, data2 + sizeof_data2, ostream_iterator<int>(cout, "\n"));
    	return(0);
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. cont' undeclared
    By HotMustardGas in forum C++ Programming
    Replies: 5
    Last Post: 06-12-2005, 04:13 PM
  2. WTF is wrong with people
    By axon in forum A Brief History of Cprogramming.com
    Replies: 12
    Last Post: 03-07-2004, 01:07 PM
  3. wtf is wrong with msdn
    By Shadow12345 in forum A Brief History of Cprogramming.com
    Replies: 4
    Last Post: 09-29-2002, 05:59 PM
  4. Wtf??? 7/9*9 = 0???
    By Tyrael in forum C++ Programming
    Replies: 2
    Last Post: 11-13-2001, 10:41 PM