why std::scan_is emits runtime error in visual studio compiler? - c++

The example here emits a runtime error with memory access violation in Visual Studio 2013.
#include <locale>
#include <iostream>
#include <iterator>
int main()
{
auto& f = std::use_facet<std::ctype<char>>(std::locale(""));
// skip until the first letter
char s1[] = " \t\t\n Test";
const char* p1 = f.scan_is(std::ctype_base::alpha, std::begin(s1), std::end(s1));
std::cout << "'" << p1 << "'\n";
// skip until the first letter
char s2[] = "123456789abcd";
const char* p2 = f.scan_is(std::ctype_base::alpha, std::begin(s2), std::end(s2));
std::cout << "'" << p2 << "'\n";
}
Why is that? Wrong implementation from the compiler?

The line auto& f = std::use_facet<std::ctype<char>>(std::locale("")); causes the error. The reference f is an alias for a null object. It seems that this implementation works for gcc C+11 and above compilers but it does not work in Microsoft compilers. Thus the right implementation in Visual Studio 2013 & 2015 which i tested, is:
#include "stdafx.h"
#include <locale>
#include <iostream>
#include <iterator>
int main()
{
std::locale loc(std::locale(""));
//auto& f = std::use_facet<std::ctype<char>>(std::locale(""));
auto& f = std::use_facet<std::ctype<char>>(loc);
// skip until the first letter
char s1[] = " \t\t\n Test";
const char* p1 = f.scan_is(std::ctype_base::alpha, std::begin(s1), std::end(s1));
std::cout << "'" << p1 << "'\n";
// skip until the first letter
char s2[] = "123456789abcd";
const char* p2 = f.scan_is(std::ctype_base::alpha, std::begin(s2), std::end(s2));
std::cout << "'" << p2 << "'\n";
}

Related

g++: crash when accessing ostringstream::str().c_str()

The code below fails on gcc 9.4.0. Is this just a bug, or have I done something stupid?
log declares an ostringstream object, writes a filename and a line number to it, and attempts to do something with the object's underlying str().c_str().
Valgrind shows this crashing at the pointer access. The output I get is:
foo.cc, line 100
cptr is at 0x55c45e8f00c0, and is
#include <iostream>
#include <sstream>
#include <cstdarg>
using std::cout;
using std::ostringstream;
void log(const char *fname, int lineno) {
ostringstream outstr;
outstr << fname << ", line " << lineno;
cout << outstr.str() << '\n'; // prints Ok
const char *cptr = outstr.str().c_str();
cout << "cptr is at " << (void*) cptr << ", and is " << cptr; // crash
}
int main() {
log("foo.cc", 100);
}
std::ostringstream::str() returns a temporary string which will be destructed at the end of the line, this then means cptr is a dangling pointer.
Try:
std::string str = outstr.str();
const char *cptr = str.c_str();
cout << "cptr is at " << (void*) cptr << ", and is " << cptr;

Lexical_cast throws exception

boost::lexical_cast throwing exception during converting string to int8_t, but int32_t - norm.
What can be wrong with int8_t ?
#include <iostream>
#include <cstdlib>
#include <boost/lexical_cast.hpp>
int main()
{
try
{
const auto a = boost::lexical_cast<int8_t>("22");
std::cout << a << std::endl;
}
catch( std::exception &e )
{
std::cout << "e=" << e.what() << std::endl;
}
}
For boost::lexical_cast, the character type of the underlying stream is assumed to be char unless either the Source or the Target requires wide-character streaming, in which case the underlying stream uses wchar_t. Following types also can use char16_t or char32_t for wide-character streaming
Boost Lexical Cast
So after doing below changes in your code:
#include <iostream>
#include <cstdlib>
#include <boost/lexical_cast.hpp>
int main()
{
try
{
const auto a = boost::lexical_cast<int8_t>("2");
const auto b = boost::lexical_cast<int16_t>("22");
std::cout << a << " and "<< b << std::endl;
}
catch( std::exception &e )
{
std::cout << "e=" << e.what() << std::endl;
}
return 0;
}
Gives below output
2 and 22
So, I feel that each character is taken as char.
So, for const auto a = boost::lexical_cast<int16_t>("2"); 2 is taken as single char which require int8_t.
And, for const auto b = boost::lexical_cast<int16_t>("22"); 22 is taken as two char values which require int16_t.
I hope it helps!

asio::buffer_cast strange output

I am learning boost::asio, and encountered a problem. Basically, asio::buffer_cast() works strange on my machine. Any help would be greatly appreciated.
I have sample code as follows,
#include <iostream>
#include <vector>
#include <sstream>
#include <iomanip>
#include <boost/asio.hpp>
int main ()
{
std::ostringstream type_stream;
type_stream << std::setw(4) << 100;
std::cout<<"type_stream:"<<type_stream.str()<<std::endl;
std::ostringstream head_stream;
head_stream << std::setw(10) << 92;
std::cout<<"head_stream:"<<head_stream.str()<<std::endl;
std::vector<boost::asio::const_buffer> buffers;
buffers.push_back(boost::asio::buffer(type_stream.str()));
buffers.push_back(boost::asio::buffer(head_stream.str()));
auto test = buffers[0];
const unsigned char* p1 = boost::asio::buffer_cast<const unsigned char*>(test);
std::cout<<"type_stream again:"<<std::string(reinterpret_cast<const char*>(p1))<<std::endl;
auto test2 = buffers[1];
const unsigned char* p2 = boost::asio::buffer_cast<const unsigned char*>(test2);
std::cout<<"head_stream again:"<<std::string(reinterpret_cast<const char*>(p2))<<std::endl;
return 0;
}
If you run this code here: https://wandbox.org/permlink/4VkxJ4TFgjHzrath, it works fine. The output is
type_stream: 100
head_stream: 92
type_stream again: 100
head_stream again: 92
But when put the code in a function and run on my machine, I got output as
type_stream: 100
head_stream: 92
type_stream again: 92
head_stream again: 92
Am I doing anything wrong in the code? It seems on my machine the second buffer covered the first one. I have gcc (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0, and the newest boost::asio.
Yes, there's Undefined Behaviour.
The problem is that
buffers.push_back(boost::asio::buffer(type_stream.str()));
the type_stream.str() returns a temporary std::string and therefore the buffer isn't valid after the push.
Fix:
Live On Coliru
#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <vector>
std::string format_buf(int v, int width) {
std::ostringstream oss;
oss << std::setw(width) << v;
return oss.str();
}
int main() {
std::string type_str = format_buf(100, 4);
std::string head_str = format_buf(92, 10);
std::cout << "type_stream first: " << std::quoted(type_str) << std::endl;
std::cout << "head_stream first: " << std::quoted(head_str) << std::endl;
std::vector<boost::asio::const_buffer> buffers;
buffers.push_back(boost::asio::buffer(type_str));
buffers.push_back(boost::asio::buffer(head_str));
auto test = buffers[0];
const unsigned char *p1 = boost::asio::buffer_cast<const unsigned char *>(test);
std::cout << "type_stream again:" << std::quoted(reinterpret_cast<const char *>(p1)) << std::endl;
auto test2 = buffers[1];
const unsigned char *p2 = boost::asio::buffer_cast<const unsigned char *>(test2);
std::cout << "head_stream again:" << std::quoted(reinterpret_cast<const char *>(p2)) << std::endl;
}
Prints
type_stream first: " 100"
head_stream first: " 92"
type_stream again:" 100"
head_stream again:" 92"
BONUS
Since you're effectively trying to do fixed-width formatting (?) why not make it simpler and more robust:
Live On Coliru
char type[4] = {};
char head[10] = {};
bio::stream<bio::array_sink> tstream(type);
tstream << 100;
bio::stream<bio::array_sink> hstream(head);
hstream << 92;
It's more robust because with your code the fields may be too wide (e.g. with type containing 12345)
With help from #sehe, the following code works. But I got new worries. Is it okay to create char type[4] = {}; char head[10] = {}; char type2[2] = {}; inside prepareBuffers() function? As the buffer was created by buffers.push_back(boost::asio::buffer(type));, I suspect type will be destroyed when goes out of prepareBuffers() function. But the in the main() the program still can access the content of buffer. Is there any copy happens?
#include <boost/asio.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <vector>
namespace bio = boost::iostreams;
void prepareBuffers(std::vector<boost::asio::const_buffer> & buffers){
char type[4] = {};
char head[10] = {};
bio::stream<bio::array_sink> tstream(type);
bio::stream<bio::array_sink> hstream(head);
tstream << 555555;
hstream << 923;
std::cout << "type_stream first: " << std::quoted(type) << std::endl;
std::cout << "head_stream first: " << std::quoted(head) << std::endl;
buffers.push_back(boost::asio::buffer(type));
buffers.push_back(boost::asio::buffer(head));
auto test = buffers[0];
const unsigned char* p1 = boost::asio::buffer_cast<const unsigned char*>(test);
std::cout<<"in function type_stream again:"<<std::string(reinterpret_cast<const char*>(p1))<<std::endl;
test = buffers[1];
const unsigned char* p2 = boost::asio::buffer_cast<const unsigned char*>(test);
std::cout<<"in function head_stream again:"<<std::string(reinterpret_cast<const char*>(p2))<<std::endl;
}
int main() {
std::vector<boost::asio::const_buffer> buffers2;
prepareBuffers(buffers2);
auto test21 = buffers2[0];
const unsigned char* p1 = boost::asio::buffer_cast<const unsigned char*>(test21);
std::cout<<"type_stream again:"<<std::string(reinterpret_cast<const char*>(p1))<<std::endl;
auto test22 = buffers2[1];
const unsigned char* p2 = boost::asio::buffer_cast<const unsigned char*>(test22);
std::cout<<"type_stream again:"<<std::string(reinterpret_cast<const char*>(p2))<<std::endl;
return 0;
}

C++ string.c_str()

If using g++ and clang++, I get ++my string==my string##my string--. While MSVC and Intel Compiler, it is ++==my string##my string--.
Why?
#include <string>
#include <iostream>
using namespace std;
string test()
{
string s0 = "my string";
return s0;
}
int main()
{
string s = test();
const char* s1 = test().c_str();
const char* s2 = s.c_str();
cout << "++" << s1 << "==" << s2 << "##" << test().c_str() << "--" << endl;
return 0;
}
Is it an undefined behavior?
In a comment, you asked:
Why test().c_str() can work but s1 not?
test().c_str() works only in some contexts, not all contexts.
std::cout << test().c_str() << std::endl;
is guaranteed to work since the temporary returned by test() is required to stay alive until the execution of the statement is complete.
On the other hand,
char const* s1 = test().c_str();
std:cout << s1 << std::endl;
is undefined behavior since the temporary is not required to live beyond completion of execution of the first line.

Lexical cast Partial conversion - Is it possible?

lexical_cast throws an exception in the following case. Is there a way to use lexical_cast and convert the string to integer.
#include <iostream>
#include "boost/lexical_cast.hpp"
#include <string>
int main()
{
std::string src = "124is";
int iNumber = boost::lexical_cast<int>(src);
std::cout << "After conversion " << iNumber << std::endl;
}
I understand, I can use atoi instead of boost::lexical_cast.
If I'm understanding your requirements correctly it seems as though removing the non-numeric elements from the string first before the lexical_cast will solve your problem. The approach I outline here makes use of the isdigit function which will return true if the given char is a digit from 0 to 9.
#include <iostream>
#include "boost/lexical_cast.hpp"
#include <string>
#include <algorithm>
#include <cctype> //for isdigit
struct is_not_digit{
bool operator()(char a) { return !isdigit(a); }
};
int main()
{
std::string src = "124is";
src.erase(std::remove_if(src.begin(),src.end(),is_not_digit()),src.end());
int iNumber = boost::lexical_cast<int>(src);
std::cout << "After conversion " << iNumber << std::endl;
}
The boost/lexical_cast uses stringstream to convert from string to other types,so you must make sure the string can be converted completely! or, it will throw the bad_lexical_cast exception,This is an example:
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
#define ERROR_LEXICAL_CAST 1
int main()
{
using boost::lexical_cast;
int a = 0;
double b = 0.0;
std::string s = "";
int e = 0;
try
{
// ----- string --> int
a = lexical_cast<int>("123");//good
b = lexical_cast<double>("123.12");//good
// -----double to string good
s = lexical_cast<std::string>("123456.7");
// ----- bad
e = lexical_cast<int>("abc");
}
catch(boost::bad_lexical_cast& e)
{
// bad lexical cast: source type value could not be interpreted as target
std::cout << e.what() << std::endl;
return ERROR_LEXICAL_CAST;
}
std::cout << a << std::endl; // cout:123
std::cout << b << std::endl; //cout:123.12
std::cout << s << std::endl; //cout:123456.7
return 0;
}