Programming Question Hello World!

Rtyh-12

New member
Joined
Sep 12, 2010
Messages
918
Reaction score
0
Points
0
Location
Kraken Mare
I don't know whether couting strings directly is any slower than creating strings and then couting those (I highly doubt it is) but the performance difference is very minor at best. As for the waiting code I gave you, well, you don't really need to understand how it works... I'm not a fan of using code I don't understand, but in my opinion it's the best method I've found, and it becomes clear after you understand classes.
 

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
Excellent, although I dont understand what any of that code does.
Reading function reference is a good way to understand what the code does.

In the example cin.sync() would clear (discard) the input buffer (note that there is also cin.clear() method, but it clears state flags and not the buffer), and cin.get() which reads a character from the buffer would wait for a new character when the input buffer is empty. On a side note cin.sync won't clear the buffer under Linux, and you should use cin.ignore there instead.
 

MeDiCS

Donator
Donator
Joined
Sep 22, 2008
Messages
602
Reaction score
2
Points
0
A piece of advice: don't ever, EVER, use code you don't understand. Besides the obvious possibility of malicious code, being pendant and detalist now will help you avoid many 'beginner mistakes' and reduce frustration.

Take this for instance:
Code:
cin.sync(); cin.get();

cin is a variable of type istream which you get when including iostream. The method sync() supposedly refill the input buffer (i.e. clears anything you've typed on the console up to that point), but it seems it may also do nothing (it's not clear from cplusplus. The C++ standard may have more details). Calling sync() is only needed if you have read from the console before that point.

get() then will block and wait for the enter key to be pressed, returning the first character from the input (which may or may not be enter: '\n'), leaving the rest in the input buffer.

Regarding this:
Code:
string Hello = "Hello world!";
cout << Hello;

// vs

cout << "Hello world!";

(WARNING: lengthy post follows)

It may make a difference on the generated code, not because they are separated, but because of the type used for Hello. The problem is that string literals have the type const char *, but you are assigning a string literal to an std::string (not the same thing). You can do this because the compiler implicitly adds code that calls the constructor for std::string. How this constructor works depends on the compiler and standard library. For GCC 4.8, on Linux, the constructor executes this beast (/usr/include/c++/4.8.0/bits/basic_string.tcc):

Code:
  template<typename _CharT, typename _Traits, typename _Alloc>
    template<typename _InIterator>
      _CharT*
      basic_string<_CharT, _Traits, _Alloc>::
      _S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a,
		   input_iterator_tag)
      {
#if _GLIBCXX_FULLY_DYNAMIC_STRING == 0
	if (__beg == __end && __a == _Alloc())
	  return _S_empty_rep()._M_refdata();
#endif
	// Avoid reallocation for common case.
	_CharT __buf[128];
	size_type __len = 0;
	while (__beg != __end && __len < sizeof(__buf) / sizeof(_CharT))
	  {
	    __buf[__len++] = *__beg;
	    ++__beg;
	  }
	_Rep* __r = _Rep::_S_create(__len, size_type(0), __a);
	_M_copy(__r->_M_refdata(), __buf, __len);
	__try
	  {
	    while (__beg != __end)
	      {
		if (__len == __r->_M_capacity)
		  {
		    // Allocate more space.
		    _Rep* __another = _Rep::_S_create(__len + 1, __len, __a);
		    _M_copy(__another->_M_refdata(), __r->_M_refdata(), __len);
		    __r->_M_destroy(__a);
		    __r = __another;
		  }
		__r->_M_refdata()[__len++] = *__beg;
		++__beg;
	      }
	  }
	__catch(...)
	  {
	    __r->_M_destroy(__a);
	    __throw_exception_again;
	  }
	__r->_M_set_length_and_sharable(__len);
	return __r->_M_refdata();
      }

(Remember that this is executed when the program starts)

What this function does is quite simple: it copies the original string to a dynamically allocated buffer. The compared code is now (simpified, in semi-pseudo code):

Code:
char *buf = new buf[128];    // Always allocate at least 128 bytes
strcpy (buf, "Hello world!");
cout << (string)buf;         // Just to show you are passing an std::string, and not a char *

// vs

cout << "Hello world!";

cout is of type ostream with the following relevant type signatures for operator<<:

Code:
ostream& operator<< (ostream& os, const char* s);
ostream& operator<< (ostream& os, const string& str);

(Both are declared outside the ostream class: see references for const char *, and std::string)

Again from GCC, the implementation for the std::string version is (/usr/include/c++/4.8.0/bits/basic_string.h):

Code:
  template<typename _CharT, typename _Traits, typename _Alloc>
    inline basic_ostream<_CharT, _Traits>&
    operator<<(basic_ostream<_CharT, _Traits>& __os,
	       const basic_string<_CharT, _Traits, _Alloc>& __str)
    {
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 586. string inserter not a formatted function
      return __ostream_insert(__os, __str.data(), __str.size());
    }

The char * version is (/usr/include/c++/4.8.0/ostream):

Code:
  template<typename _CharT, typename _Traits>
    inline basic_ostream<_CharT, _Traits>&
    operator<<(basic_ostream<_CharT, _Traits>& __out, const _CharT* __s)
    {
      if (!__s)
	__out.setstate(ios_base::badbit);
      else
	__ostream_insert(__out, __s,
			 static_cast<streamsize>(_Traits::length(__s)));
      return __out;
    }

(The function __ostream_insert() is common to both versions, so I'll not delve into it (it may not seem, but we're doing a comparison :p). For the curious (and not faint of heart), the function is defined in /usr/include/c++/4.8.0/bits/ostream_insert.h)

The difference in both versions boil down to how the length of the string is calculated. For std::strings, size(), on GCC, is practically free, accessing only a memory location.

For the the char * case, things get a bit more complicated. _Traits::length() refers to this function (/usr/include/c++/4.8.0/bits/char_traits.h):

Code:
      static size_t
      length(const char_type* __s)
      { return __builtin_strlen(__s); }

__builtin_strlen() is equivalent to strlen() except on one, very special case: when you are dealing with string literals. In that case, instead of calling strlen() at runtime, it calculates the string length at compile-time.

The compared code now becomes:

Code:
char *buf = new buf[128];
strcpy (buf, "Hello world!");
size_t size;     // This is actually calculated at the same time as strcpy()
_ostream_insert (cout, buf, size);

// vs

_ostream_insert (cout, "Hello world!", 12);

The question now is whether the compiler can see that the copy isn't needed and that the string size is 12. I won't bore you anymore than I already did (or we could delve into gas assembly and its horrific syntax...), and give a straight answer: no, at least on GCC.

On the other hand, this

Code:
const char *Hello = "Hello world!";
std::cout << Hello;

and this

Code:
std::cout << "Hello world!";

are completely equivalent.
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,617
Reaction score
2,337
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
.sync() empties the read buffer on buffered streams - like cin. This is important because from previous inputs, there might still be key presses left in the input buffer - for example end of line characters.
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
A piece of advice: don't ever, EVER, use code you don't understand. Besides the obvious possibility of malicious code, being pendant and detalist now will help you avoid many 'beginner mistakes' and reduce frustration.

Take this for instance:
Code:
cin.sync(); cin.get();

cin is a variable of type istream which you get when including iostream. The method sync() supposedly refill the input buffer (i.e. clears anything you've typed on the console up to that point), but it seems it may also do nothing (it's not clear from cplusplus. The C++ standard may have more details). Calling sync() is only needed if you have read from the console before that point.

get() then will block and wait for the enter key to be pressed, returning the first character from the input (which may or may not be enter: '\n'), leaving the rest in the input buffer.

Regarding this:
Code:
string Hello = "Hello world!";
cout << Hello;

// vs

cout << "Hello world!";

(WARNING: lengthy post follows)

It may make a difference on the generated code, not because they are separated, but because of the type used for Hello. The problem is that string literals have the type const char *, but you are assigning a string literal to an std::string (not the same thing). You can do this because the compiler implicitly adds code that calls the constructor for std::string. How this constructor works depends on the compiler and standard library. For GCC 4.8, on Linux, the constructor executes this beast (/usr/include/c++/4.8.0/bits/basic_string.tcc):

Code:
  template<typename _CharT, typename _Traits, typename _Alloc>
    template<typename _InIterator>
      _CharT*
      basic_string<_CharT, _Traits, _Alloc>::
      _S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a,
		   input_iterator_tag)
      {
#if _GLIBCXX_FULLY_DYNAMIC_STRING == 0
	if (__beg == __end && __a == _Alloc())
	  return _S_empty_rep()._M_refdata();
#endif
	// Avoid reallocation for common case.
	_CharT __buf[128];
	size_type __len = 0;
	while (__beg != __end && __len < sizeof(__buf) / sizeof(_CharT))
	  {
	    __buf[__len++] = *__beg;
	    ++__beg;
	  }
	_Rep* __r = _Rep::_S_create(__len, size_type(0), __a);
	_M_copy(__r->_M_refdata(), __buf, __len);
	__try
	  {
	    while (__beg != __end)
	      {
		if (__len == __r->_M_capacity)
		  {
		    // Allocate more space.
		    _Rep* __another = _Rep::_S_create(__len + 1, __len, __a);
		    _M_copy(__another->_M_refdata(), __r->_M_refdata(), __len);
		    __r->_M_destroy(__a);
		    __r = __another;
		  }
		__r->_M_refdata()[__len++] = *__beg;
		++__beg;
	      }
	  }
	__catch(...)
	  {
	    __r->_M_destroy(__a);
	    __throw_exception_again;
	  }
	__r->_M_set_length_and_sharable(__len);
	return __r->_M_refdata();
      }

(Remember that this is executed when the program starts)

What this function does is quite simple: it copies the original string to a dynamically allocated buffer. The compared code is now (simpified, in semi-pseudo code):

Code:
char *buf = new buf[128];    // Always allocate at least 128 bytes
strcpy (buf, "Hello world!");
cout << (string)buf;         // Just to show you are passing an std::string, and not a char *

// vs

cout << "Hello world!";

cout is of type ostream with the following relevant type signatures for operator<<:

Code:
ostream& operator<< (ostream& os, const char* s);
ostream& operator<< (ostream& os, const string& str);

(Both are declared outside the ostream class: see references for const char *, and std::string)

Again from GCC, the implementation for the std::string version is (/usr/include/c++/4.8.0/bits/basic_string.h):

Code:
  template<typename _CharT, typename _Traits, typename _Alloc>
    inline basic_ostream<_CharT, _Traits>&
    operator<<(basic_ostream<_CharT, _Traits>& __os,
	       const basic_string<_CharT, _Traits, _Alloc>& __str)
    {
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 586. string inserter not a formatted function
      return __ostream_insert(__os, __str.data(), __str.size());
    }

The char * version is (/usr/include/c++/4.8.0/ostream):

Code:
  template<typename _CharT, typename _Traits>
    inline basic_ostream<_CharT, _Traits>&
    operator<<(basic_ostream<_CharT, _Traits>& __out, const _CharT* __s)
    {
      if (!__s)
	__out.setstate(ios_base::badbit);
      else
	__ostream_insert(__out, __s,
			 static_cast<streamsize>(_Traits::length(__s)));
      return __out;
    }

(The function __ostream_insert() is common to both versions, so I'll not delve into it (it may not seem, but we're doing a comparison :p). For the curious (and not faint of heart), the function is defined in /usr/include/c++/4.8.0/bits/ostream_insert.h)

The difference in both versions boil down to how the length of the string is calculated. For std::strings, size(), on GCC, is practically free, accessing only a memory location.

For the the char * case, things get a bit more complicated. _Traits::length() refers to this function (/usr/include/c++/4.8.0/bits/char_traits.h):

Code:
      static size_t
      length(const char_type* __s)
      { return __builtin_strlen(__s); }

__builtin_strlen() is equivalent to strlen() except on one, very special case: when you are dealing with string literals. In that case, instead of calling strlen() at runtime, it calculates the string length at compile-time.

The compared code now becomes:

Code:
char *buf = new buf[128];
strcpy (buf, "Hello world!");
size_t size;     // This is actually calculated at the same time as strcpy()
_ostream_insert (cout, buf, size);

// vs

_ostream_insert (cout, "Hello world!", 12);

The question now is whether the compiler can see that the copy isn't needed and that the string size is 12. I won't bore you anymore than I already did (or we could delve into gas assembly and its horrific syntax...), and give a straight answer: no, at least on GCC.

On the other hand, this

Code:
const char *Hello = "Hello world!";
std::cout << Hello;

and this

Code:
std::cout << "Hello world!";

are completely equivalent.

Okay, you lost me completely there, point made about not using code you dont understand.


Reading function reference is a good way to understand what the code does.

In the example cin.sync() would clear (discard) the input buffer (note that there is also cin.clear() method, but it clears state flags and not the buffer), and cin.get() which reads a character from the buffer would wait for a new character when the input buffer is empty. On a side note cin.sync won't clear the buffer under Linux, and you should use cin.ignore there instead.

It never occurred to me that functions like this might have a reference header like the OrbiterSDK does. Ill have to check that out then.

:hailprobe:
 

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
It never occurred to me that functions like this might have a reference header like the OrbiterSDK does. Ill have to check that out then.
By function reference I didn't mean a header file where the function was declared, optionally with a description for doxygen to generate an OrbiterSDK like function reference, but a generic documentation for the Standard C++ Library.

Every library that can be used by a programmer should have a documentation with function reference, otherwise nobody would want or know how to use it (methods or class names alone usually don't tell what they are, contain, or do, and you don't have time to step through the generated machine code in debugger to check what every singe function is for).

You can find what functions do either by searching them on Google or other search provider, or directly by searching them at one of well known sites containing these function references, like Standard C++ Library reference at cplusplus.com, for example:
 
Top