Skip to main content
edited body
Source Link
Snowhawk
  • 6.3k
  • 1
  • 18
  • 33

std::[o]stringstream vs std::string::append()/std::string::operator+=()

With std::string::append(), you'll usually pay the initial allocation, and with each append you'll pay for a data copy and possibly an allocation. Constructing std::ostringstream is more complex compared to string. You have to initialize the stream, the states, and the locale. Every std::ostringstream::operator<<() call accrues a possible allocation, a data copy, and state checks. Once you've completed that, you have to invoke std::stringstream::str() to use the string, which involves a copy (depending on implementation).

With C++11 introducing non-member std::to_string() and std::stoXX() conversion functions and all the various format libraries out there, I haven't really found a use for std::ostringstream recently.

Explicit Typing

std::stringstream inherits from both std::istringstream and std::ostringstream. You'll find that rarely will you have to both read and write from a stream, so be explicit in your intent and use the std::[i|o]stringstream type.

Interface

vectorSubstr() could be confusing for some people. Does it return a std::vector<std::string> of substrings? Consider other names like to_string(), join(), concatenate().

Prefer writing range-based algorithms using the Iterator pattern that is heavily used by the STL.

If you do not plan on changing the contents of a parameter, const-qualify it.

Your parameter for the container is taken By-Value. Copies on containers (and non-primitives) can be expensive, so pass those arguments By-Reference (&).

std::string join(const std::vector<std::string> &input, const char separator)

Algorithm

You can reduce the amount of branching you have to do by handling the first element case, then your delimiter becomes naturally infixed.

Putting It Together

template <typename InputIterator, typename Separator>
inline typename std::iterator_traits<InputIterator>::value_type
join(InputIterator first, InputIterator last, const Separator& separator) {
  using ResultType = std::iterator_traits<InputIterator>::value_type;
  ResultType result;

  if (first != last) {
    result += *first;
    ++first;
  }

  for (; first != last; ++first) {
    result += separator;
    result += *first;
  }

  return result;
}

int main() {
  const std::vector<std::string> inputs = {"a", "bcd", "efghijklm", "nopqrstuvwxyz"};
  const auto first = std::next(std::begin(inputs), 2);
  const auto last = std::end(inputs);

  std::cout << join(first, last, ", ") << '\n';
}

std::[o]stringstream vs std::string::append()/std::string::operator+=()

With std::string::append(), you'll usually pay the initial allocation, and with each append you'll pay for a data copy and possibly an allocation. Constructing std::ostringstream is more complex compared to string. You have to initialize the stream, the states, and the locale. Every std::ostringstream::operator<<() call accrues a possible allocation, a data copy, and state checks.

With C++11 introducing non-member std::to_string() and std::stoXX() conversion functions and all the various format libraries out there, I haven't really found a use for std::ostringstream recently.

Explicit Typing

std::stringstream inherits from both std::istringstream and std::ostringstream. You'll find that rarely will you have to both read and write from a stream, so be explicit in your intent and use the std::[i|o]stringstream type.

Interface

vectorSubstr() could be confusing for some people. Does it return a std::vector<std::string> of substrings? Consider other names like to_string(), join(), concatenate().

Prefer writing range-based algorithms using the Iterator pattern that is heavily used by the STL.

If you do not plan on changing the contents of a parameter, const-qualify it.

Your parameter for the container is taken By-Value. Copies on containers (and non-primitives) can be expensive, so pass those arguments By-Reference (&).

std::string join(const std::vector<std::string> &input, const char separator)

Algorithm

You can reduce the amount of branching you have to do by handling the first element case, then your delimiter becomes naturally infixed.

Putting It Together

template <typename InputIterator, typename Separator>
inline typename std::iterator_traits<InputIterator>::value_type
join(InputIterator first, InputIterator last, const Separator& separator) {
  using ResultType = std::iterator_traits<InputIterator>::value_type;
  ResultType result;

  if (first != last) {
    result += *first;
    ++first;
  }

  for (; first != last; ++first) {
    result += separator;
    result += *first;
  }

  return result;
}

int main() {
  const std::vector<std::string> inputs = {"a", "bcd", "efghijklm", "nopqrstuvwxyz"};
  const auto first = std::next(std::begin(inputs), 2);
  const auto last = std::end(inputs);

  std::cout << join(first, last, ", ") << '\n';
}

std::[o]stringstream vs std::string::append()/std::string::operator+=()

With std::string::append(), you'll usually pay the initial allocation, and with each append you'll pay for a data copy and possibly an allocation. Constructing std::ostringstream is more complex compared to string. You have to initialize the stream, the states, and the locale. Every std::ostringstream::operator<<() call accrues a possible allocation, a data copy, and state checks. Once you've completed that, you have to invoke std::stringstream::str() to use the string, which involves a copy (depending on implementation).

With C++11 introducing non-member std::to_string() and std::stoXX() conversion functions and all the various format libraries out there, I haven't really found a use for std::ostringstream recently.

Explicit Typing

std::stringstream inherits from both std::istringstream and std::ostringstream. You'll find that rarely will you have to both read and write from a stream, so be explicit in your intent and use the std::[i|o]stringstream type.

Interface

vectorSubstr() could be confusing for some people. Does it return a std::vector<std::string> of substrings? Consider other names like to_string(), join(), concatenate().

Prefer writing range-based algorithms using the Iterator pattern that is heavily used by the STL.

If you do not plan on changing the contents of a parameter, const-qualify it.

Your parameter for the container is taken By-Value. Copies on containers (and non-primitives) can be expensive, so pass those arguments By-Reference (&).

std::string join(const std::vector<std::string> &input, const char separator)

Algorithm

You can reduce the amount of branching you have to do by handling the first element case, then your delimiter becomes naturally infixed.

Putting It Together

template <typename InputIterator, typename Separator>
inline typename std::iterator_traits<InputIterator>::value_type
join(InputIterator first, InputIterator last, const Separator& separator) {
  using ResultType = std::iterator_traits<InputIterator>::value_type;
  ResultType result;

  if (first != last) {
    result += *first;
    ++first;
  }

  for (; first != last; ++first) {
    result += separator;
    result += *first;
  }

  return result;
}

int main() {
  const std::vector<std::string> inputs = {"a", "bcd", "efghijklm", "nopqrstuvwxyz"};
  const auto first = std::next(std::begin(inputs), 2);
  const auto last = std::end(inputs);

  std::cout << join(first, last, ", ") << '\n';
}
edited body
Source Link
Snowhawk
  • 6.3k
  • 1
  • 18
  • 33

std::[o]stringstream vs std::string::append()/std::string::operator+=()

With std::string::append(), you'll usually pay the initial allocation, and with each append you'll pay for a data copy and possibly an allocation. Constructing std::ostringstream is more complex compared to string. You have to initialize the stream, the states, and the locale. Every std::ostringstream::operator<<() call accrues a possible allocation, a data copy, and state checks.

With C++11 introducing non-member std::to_string() and std::stoXX() conversion functions and all the various format libraries out there, I haven't really found a use for std::ostringstream recently.

Explicit Typing

std::stringstream inherits from both std::istringstream and std::ostringstream. You'll find that rarely will you have to both read and write from a stream, so be explicit in your intent and use the std::[i|o]stringstream type.

Interface

vectorSubstr() could be confusing for some people. Does it return a std::vector<std::string> of substrings? Consider other names like to_string(), join(), concatenate().

Prefer writing range-based algorithms using the Iterator pattern that is heavily used by the STL.

If you do not plan on changing the contents of a parameter, const-qualify it.

Your parameter for the container is taken By-Value. Copies on containers (and non-primitives) can be expensive, so pass those arguments By-Reference (&).

std::string join(const std::vector<std::string> &input, const char separator)

Algorithm

You can reduce the amount of branching you have to do by handling the first element case, then your delimiter becomes naturally infixed.

Putting It Together

template <typename InputIterator, typename Separator>
inline typename std::iterator_traits<InputIterator>::value_type
join(InputIterator first, InputIterator last, const Seperator&Separator& seperatorseparator) {
  using ResultType = std::iterator_traits<InputIterator>::value_type;
  ResultType result;

  if (first != last) {
    result += *first;
    ++first;
  }

  for (; first != last; ++first) {
    result += seperator;separator;
    result += *first;
  }

  return result;
}

int main() {
  const std::vector<std::string> inputs = {"a", "bcd", "efghijklm", "nopqrstuvwxyz"};
  const auto first = std::next(std::begin(inputs), 2);
  const auto last = std::end(inputs);

  std::cout << join(first, last, ", ") << '\n';
}

std::[o]stringstream vs std::string::append()/std::string::operator+=()

With std::string::append(), you'll usually pay the initial allocation, and with each append you'll pay for a data copy and possibly an allocation. Constructing std::ostringstream is more complex compared to string. You have to initialize the stream, the states, and the locale. Every std::ostringstream::operator<<() call accrues a possible allocation, a data copy, and state checks.

With C++11 introducing non-member std::to_string() and std::stoXX() conversion functions and all the various format libraries out there, I haven't really found a use for std::ostringstream recently.

Explicit Typing

std::stringstream inherits from both std::istringstream and std::ostringstream. You'll find that rarely will you have to both read and write from a stream, so be explicit in your intent and use the std::[i|o]stringstream type.

Interface

vectorSubstr() could be confusing for some people. Does it return a std::vector<std::string> of substrings? Consider other names like to_string(), join(), concatenate().

Prefer writing range-based algorithms using the Iterator pattern that is heavily used by the STL.

If you do not plan on changing the contents of a parameter, const-qualify it.

Your parameter for the container is taken By-Value. Copies on containers (and non-primitives) can be expensive, so pass those arguments By-Reference (&).

std::string join(const std::vector<std::string> &input, const char separator)

Algorithm

You can reduce the amount of branching you have to do by handling the first element case, then your delimiter becomes naturally infixed.

Putting It Together

template <typename InputIterator, typename Separator>
inline typename std::iterator_traits<InputIterator>::value_type
join(InputIterator first, InputIterator last, const Seperator& seperator) {
  using ResultType = std::iterator_traits<InputIterator>::value_type;
  ResultType result;

  if (first != last) {
    result += *first;
    ++first;
  }

  for (; first != last; ++first) {
    result += seperator;
    result += *first;
  }

  return result;
}

int main() {
  const std::vector<std::string> inputs = {"a", "bcd", "efghijklm", "nopqrstuvwxyz"};
  const auto first = std::next(std::begin(inputs), 2);
  const auto last = std::end(inputs);

  std::cout << join(first, last, ", ") << '\n';
}

std::[o]stringstream vs std::string::append()/std::string::operator+=()

With std::string::append(), you'll usually pay the initial allocation, and with each append you'll pay for a data copy and possibly an allocation. Constructing std::ostringstream is more complex compared to string. You have to initialize the stream, the states, and the locale. Every std::ostringstream::operator<<() call accrues a possible allocation, a data copy, and state checks.

With C++11 introducing non-member std::to_string() and std::stoXX() conversion functions and all the various format libraries out there, I haven't really found a use for std::ostringstream recently.

Explicit Typing

std::stringstream inherits from both std::istringstream and std::ostringstream. You'll find that rarely will you have to both read and write from a stream, so be explicit in your intent and use the std::[i|o]stringstream type.

Interface

vectorSubstr() could be confusing for some people. Does it return a std::vector<std::string> of substrings? Consider other names like to_string(), join(), concatenate().

Prefer writing range-based algorithms using the Iterator pattern that is heavily used by the STL.

If you do not plan on changing the contents of a parameter, const-qualify it.

Your parameter for the container is taken By-Value. Copies on containers (and non-primitives) can be expensive, so pass those arguments By-Reference (&).

std::string join(const std::vector<std::string> &input, const char separator)

Algorithm

You can reduce the amount of branching you have to do by handling the first element case, then your delimiter becomes naturally infixed.

Putting It Together

template <typename InputIterator, typename Separator>
inline typename std::iterator_traits<InputIterator>::value_type
join(InputIterator first, InputIterator last, const Separator& separator) {
  using ResultType = std::iterator_traits<InputIterator>::value_type;
  ResultType result;

  if (first != last) {
    result += *first;
    ++first;
  }

  for (; first != last; ++first) {
    result += separator;
    result += *first;
  }

  return result;
}

int main() {
  const std::vector<std::string> inputs = {"a", "bcd", "efghijklm", "nopqrstuvwxyz"};
  const auto first = std::next(std::begin(inputs), 2);
  const auto last = std::end(inputs);

  std::cout << join(first, last, ", ") << '\n';
}
added 13 characters in body
Source Link
Snowhawk
  • 6.3k
  • 1
  • 18
  • 33

std::[o]stringstream vs std::string::append()/std::string::operator+=()

With std::string::append(), you'll usually pay the initial allocation, and with each append you'll pay for a data copy and possibly an allocation. Constructing std::ostringstream is more complex compared to string. You have to initialize the stream, the states, and the locale. Every std::ostringstream::operator<<() call accrues a possible allocation, a data copy, and state checks.

With C++11 introducing non-member std::to_string() and std::stoXX() conversion functions and all the various format libraries out there, I haven't really found a use for std::ostringstream recently.

Explicit Typing

std::stringstream inherits from both std::istringstream and std::ostringstream. You'll find that rarely will you have to both read and write from a stream, so be explicit in your intent and use the std::[i|o]stringstream type.

Interface

vectorSubstr() could be confusing for some people. Does it return a std::vector<std::string> of substrings? Consider other names like to_string(), join(), concatenate().

Prefer writing range-based algorithms using the Iterator pattern that is heavily used by the STL.

If you do not plan on changing the contents of a parameter, Constconst-qualify it.

Your parameter for the container is taken By-Value. Copies on containers (and non-primitives) can be expensive, so pass those arguments By-Reference (&).

std::string join(const std::vector<std::string> &input, const char separator)

Algorithm

You can reduce the amount of branching you have to do by handling the first element case, then handling every other delimited caseyour delimiter becomes naturally infixed.

Putting It Together

template <typename InputIterator, typename Separator>
inline typename std::iterator_traits<InputIterator>::value_type
join(InputIterator first, InputIterator last, const Seperator& seperator) {
  using ResultType = std::iterator_traits<InputIterator>::value_type;
  ResultType result;

  if (first != last) {
    result += *first;
    ++first;
  }

  for (; first != last; ++first) {
    result += seperator;
    result += *first;
  }

  return result;
}

int main() {
  const std::vector<std::string> inputs = {"a", "bcd", "efghijklm", "nopqrstuvwxyz"};
  const auto first = std::next(std::begin(inputs), 2);
  const auto last = std::end(inputs);

  std::cout << join(first, last, ", ") << '\n';
}

std::[o]stringstream vs std::string::append()/std::string::operator+=()

With std::string::append(), you'll usually pay the initial allocation, and with each append you'll pay for a data copy and possibly an allocation. Constructing std::ostringstream is more complex compared to string. You have to initialize the stream, the states, and the locale. Every std::ostringstream::operator<<() call accrues a possible allocation, a data copy, and state checks.

With C++11 introducing non-member std::to_string() and std::stoXX() conversion functions and all the various format libraries out there, I haven't really found a use for std::ostringstream recently.

Explicit Typing

std::stringstream inherits from both std::istringstream and std::ostringstream. You'll find that rarely will you have to both read and write from a stream, so be explicit in your intent and use the std::[i|o]stringstream type.

Interface

vectorSubstr() could be confusing for some people. Does it return a std::vector<std::string> of substrings? Consider other names like to_string(), join(), concatenate().

Prefer writing range-based algorithms using the Iterator pattern that is heavily used by the STL.

If you do not plan on changing the contents of a parameter, Const-qualify it.

Your parameter for the container is taken By-Value. Copies on containers (and non-primitives) can be expensive, so pass those arguments By-Reference.

std::string join(const std::vector<std::string> &input, const char separator)

Algorithm

You can reduce the amount of branching you have to do by handling the first element case, then handling every other delimited case.

Putting It Together

template <typename InputIterator, typename Separator>
inline typename std::iterator_traits<InputIterator>::value_type
join(InputIterator first, InputIterator last, const Seperator& seperator) {
  using ResultType = std::iterator_traits<InputIterator>::value_type;
  ResultType result;

  if (first != last) {
    result += *first;
    ++first;
  }

  for (; first != last; ++first) {
    result += seperator;
    result += *first;
  }

  return result;
}

int main() {
  const std::vector<std::string> inputs = {"a", "bcd", "efghijklm", "nopqrstuvwxyz"};
  const auto first = std::next(std::begin(inputs), 2);
  const auto last = std::end(inputs);

  std::cout << join(first, last, ", ") << '\n';
}

std::[o]stringstream vs std::string::append()/std::string::operator+=()

With std::string::append(), you'll usually pay the initial allocation, and with each append you'll pay for a data copy and possibly an allocation. Constructing std::ostringstream is more complex compared to string. You have to initialize the stream, the states, and the locale. Every std::ostringstream::operator<<() call accrues a possible allocation, a data copy, and state checks.

With C++11 introducing non-member std::to_string() and std::stoXX() conversion functions and all the various format libraries out there, I haven't really found a use for std::ostringstream recently.

Explicit Typing

std::stringstream inherits from both std::istringstream and std::ostringstream. You'll find that rarely will you have to both read and write from a stream, so be explicit in your intent and use the std::[i|o]stringstream type.

Interface

vectorSubstr() could be confusing for some people. Does it return a std::vector<std::string> of substrings? Consider other names like to_string(), join(), concatenate().

Prefer writing range-based algorithms using the Iterator pattern that is heavily used by the STL.

If you do not plan on changing the contents of a parameter, const-qualify it.

Your parameter for the container is taken By-Value. Copies on containers (and non-primitives) can be expensive, so pass those arguments By-Reference (&).

std::string join(const std::vector<std::string> &input, const char separator)

Algorithm

You can reduce the amount of branching you have to do by handling the first element case, then your delimiter becomes naturally infixed.

Putting It Together

template <typename InputIterator, typename Separator>
inline typename std::iterator_traits<InputIterator>::value_type
join(InputIterator first, InputIterator last, const Seperator& seperator) {
  using ResultType = std::iterator_traits<InputIterator>::value_type;
  ResultType result;

  if (first != last) {
    result += *first;
    ++first;
  }

  for (; first != last; ++first) {
    result += seperator;
    result += *first;
  }

  return result;
}

int main() {
  const std::vector<std::string> inputs = {"a", "bcd", "efghijklm", "nopqrstuvwxyz"};
  const auto first = std::next(std::begin(inputs), 2);
  const auto last = std::end(inputs);

  std::cout << join(first, last, ", ") << '\n';
}
added 958 characters in body
Source Link
Snowhawk
  • 6.3k
  • 1
  • 18
  • 33
Loading
added 958 characters in body
Source Link
Snowhawk
  • 6.3k
  • 1
  • 18
  • 33
Loading
Source Link
Snowhawk
  • 6.3k
  • 1
  • 18
  • 33
Loading