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:
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
). 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.