I've recently decided to use boost::asio for my sockets, but now I'm running into a problem: documentation seems to be lacking.
What I want to do is write a function that will send a message consisting of the following structure:
2 bytes of an unsigned integer (uint16_t) for an opcode all bytes
all bytes after that (a flexible amount) being any type of data (cast to void*). This data will be operated upon based on the opcode
For example, if the opcode is 1, perhaps defined as OPCODE_LOGIN, then the bytes following the opcode could contain a string containing login information, etc.
bool sendMessage(tcp::socket* sock, uint16_t opcode, void* data)
{
void* fullData = malloc(sizeof(uint16_t) + sizeof(data));
memcpy(fullData, (void*)opcode, sizeof(opcode));
memcpy(&fullData + sizeof(uint16_t), data, sizeof(data));
boost::asio::write(sock, boost::asio::buffer(fullData, sizeof(fullData)));
// by the way, at this point, is it safe to delete fullData to prevent memory leaks?
return true;
}
This does not compile, however. I get a cryptic compilation error regarding the call to write:
1>------ Build started: Project: client, Configuration: Debug Win32 ------
1> main.cpp
1>c:\boost\boost_1_47\boost\asio\impl\write.hpp(46): error C2228: left of '.write_some' must have class/struct/union
1> type is 'boost::asio::basic_stream_socket<Protocol> '
1> with
1> [
1> Protocol=boost::asio::ip::tcp
1> ]
1> did you intend to use '->' instead?
1> c:\boost\boost_1_47\boost\asio\impl\write.hpp(59) : see reference to function template instantiation 'size_t boost::asio::write<SyncWriteStream,ConstBufferSequence,boost::asio::detail::transfer_all_t>(SyncWriteStream &,const ConstBufferSequence &,CompletionCondition,boost::system::error_code &)' being compiled
1> with
1> [
1> SyncWriteStream=boost::asio::ip::tcp::socket *,
1> ConstBufferSequence=boost::asio::mutable_buffers_1,
1> CompletionCondition=boost::asio::detail::transfer_all_t
1> ]
1> c:\users\josh\documents\visual studio 2010\projects\client\client\main.cpp(53) : see reference to function template instantiation 'size_t boost::asio::write<boost::asio::ip::tcp::socket*,boost::asio::mutable_buffers_ 1>(SyncWriteStream &,const ConstBufferSequence &)' being compiled
1> with
1> [
1> SyncWriteStream=boost::asio::ip::tcp::socket *,
1> ConstBufferSequence=boost::asio::mutable_buffers_1
1> ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
As you can see, the error message points directly into Boost's write.hpp file, and not to any of my own code.. I believe I'm calling write() incorrectly in some way, but after a solid hour of googling and researching references and examples (all of which either use another overloaded write() or are using data with specifically defined sizes/structures), I haven't been able to determine what exactly I'm doing wrong here.
Can someone help me debug this compilation error?
documentation seems to be lacking
The highest voted question in boost-asio is about documentation, start there :-)
Can someone help me debug this compilation error?
The write() free function expects a reference type as the first parameter. Not a pointer as you have in your example
bool sendMessage(tcp::socket* sock, uint16_t opcode, void* data)
{
void* fullData = malloc(sizeof(uint16_t) + sizeof(data));
memcpy(fullData, (void*)opcode, sizeof(opcode));
memcpy(&fullData + sizeof(uint16_t), data, sizeof(data));
boost::asio::write(*sock, boost::asio::buffer(fullData, sizeof(fullData)));
// ^^^^ correct type now
// by the way, at this point, is it safe to delete fullData to prevent memory leaks?
return true;
}
at this point, is it safe to delete fullData to prevent memory leaks?
Yes, write() is a blocking call. It is done with your buffer when the call returns. I strongly suggest making this code exception safe however, look into using new and a boost::scoped_array if you wish to create your buffer with dynamic storage duration.
Related
I'm taking up some folks advice and looking into the fmt library:
http://fmtlib.net
It appears to have the features I need, and claims to support %p (pointer), but when compiling my code which uses a %p I get a long string of template errors (incomprehensible). I'll post them at the end of this.
if I pull out the %p and the corresponding pointer argument, then it compiles on VS2017 c++17.
However, I'm at a loss as to how to either decode the template errors, or to get some insight as to why it won't accept a %p argument in the first place.
I've tried casting the argument to a (void*) - same issue.
I've tried using the python style syntax in the formatter {} - same issue.
I've broken out the %p bits separately from the rest of the formatting - same issue.
I see that there is support for user-types - but in this case I just want to output this as a raw pointer value. I could just skip it, after all how valuable can the pointer address be, really? But of course that means more work during conversion from sprintf to fmt::format to hunt down all %p and "do something with them" such as elide them.
But the docs seem to indicate that %p is supported - http://fmtlib.net/latest/syntax.html (about 3/4 of the way down - search on 'pointer' or 'p').
Here's the calling function: (note: pAccels is declared as const ACCEL *)
m_hAccel = ::CreateAcceleratorTable(const_cast<LPACCEL>(pAccels), (int)count);
if (!m_hAccel)
{
auto error = GetLastError();
throw CWinAPIErrorException(__FUNCTION__, "CreateAcceleratorTable", fmt::format("%p,%u", pAccels, count), error);
}
Here's the diagnostic spewage:
1>c:\users\steve\source\fmt\include\fmt\core.h(1073): error C2825: 'fmt::v5::internal::get_type<Context,Arg>::value_type': must be a class or namespace when followed by '::'
1> with
1> [
1> Context=fmt::v5::basic_format_context<std::back_insert_iterator<fmt::v5::internal::buffer<char>>,char>,
1> Arg=const ACCEL *
1> ]
1>c:\users\steve\source\fmt\include\fmt\core.h(1081): note: see reference to class template instantiation 'fmt::v5::internal::get_type<Context,Arg>' being compiled
1> with
1> [
1> Context=fmt::v5::basic_format_context<std::back_insert_iterator<fmt::v5::internal::buffer<char>>,char>,
1> Arg=const ACCEL *
1> ]
1>c:\users\steve\source\fmt\include\fmt\core.h(1190): note: see reference to function template instantiation 'unsigned __int64 fmt::v5::internal::get_types<Context,const ACCEL*,size_t>(void)' being compiled
1> with
1> [
1> Context=fmt::v5::basic_format_context<std::back_insert_iterator<fmt::v5::internal::buffer<char>>,char>
1> ]
1>c:\users\steve\source\fmt\include\fmt\core.h(1190): note: while compiling class template member function 'unsigned __int64 fmt::v5::format_arg_store<fmt::v5::basic_format_context<std::back_insert_iterator<fmt::v5::internal::buffer<Char>>,Char>,const ACCEL *,size_t>::get_types(void)'
1> with
1> [
1> Char=char
1> ]
1>c:\users\steve\source\fmt\include\fmt\core.h(1478): note: see reference to class template instantiation 'fmt::v5::format_arg_store<fmt::v5::basic_format_context<std::back_insert_iterator<fmt::v5::internal::buffer<Char>>,Char>,const ACCEL *,size_t>' being compiled
1> with
1> [
1> Char=char
1> ]
1>c:\users\steve\source\tbx\wapi\acceleratortable.cpp(58): note: see reference to function template instantiation 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> fmt::v5::format<char[6],const ACCEL*,size_t,0>(const S (&),const ACCEL *const &,const size_t &)' being compiled
1> with
1> [
1> S=char [6]
1> ]
1>c:\users\steve\source\fmt\include\fmt\core.h(1073): error C2510: 'value_type': left of '::' must be a class/struct/union
1>c:\users\steve\source\fmt\include\fmt\core.h(1073): error C2065: 'type_tag': undeclared identifier
1>c:\users\steve\source\fmt\include\fmt\core.h(1073): error C2131: expression did not evaluate to a constant
1>c:\users\steve\source\fmt\include\fmt\core.h(1073): note: a non-constant (sub-)expression was encountered
1>c:\users\steve\source\fmt\include\fmt\core.h(1197): error C2131: expression did not evaluate to a constant
1>c:\users\steve\source\fmt\include\fmt\core.h(1082): note: failure was caused by non-constant arguments or reference to a non-constant symbol
1>c:\users\steve\source\fmt\include\fmt\core.h(1082): note: see usage of 'value'
To format a pointer you can either cast it to void*:
std::string s = fmt::format("{},{}", static_cast<void*>(pAccels), count);
or wrap it in fmt::ptr:
std::string s = fmt::format("{},{}", fmt::ptr(pAccels), count);
Working example on godbolt: https://godbolt.org/z/sCNbjr
Note that format uses Python-like format string syntax, not printf's and returns a std::string object.
I am trying to write some data to different files for each index. i.e. The file name should change from datafile0.res to datafile99.res depending on the index passed.
I am using visual C++ 2008.
The code is:
void write_data(int index) {
ofstream coutput;
// first i need to convert integer index to string. Not sure if right?
ostringstream temp;
temp<<index;
std::string s = temp.str();
std::string dir = "C:\My_Data\datafile" + s + ".res";
coutput.open(dir);
When i run this code, the following error appears:
error C2664: 'void std::basic_ofstream<_Elem,_Traits>::open(const wchar_t ,std::ios_base::openmode,int)' : cannot convert parameter 1 from 'std::string' to 'const wchar_t *'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called.
Please need your help.
Thanks in advance
This has nothing to do with your stated goal, or your concatenation.
std::fstream::open, before C++11, requires a const char*, not an std::string.
So:
coutput.open(dir.c_str());
I'm have a problem with *passing a deleter functor into a std::smart_ptr*. This is the first time I've tried anything like this, so I may be overlooking something very simple..
Here's what my functor class looks like;
#pragma once;
#ifndef ASSETDELETERS_H
#define ASSETDELETERS_H
#include "RenderSystem.h"
struct SourceImageDeleter
{
RenderSystem & refGraphicsRenderer;
unsigned int * ptrTextureID;
explicit SourceImageDeleter( RenderSystem & tempRef, unsigned int * tempPtrID )
: refGraphicsRenderer( tempRef ) ,
ptrTextureID(tempPtrID) {};
SourceImageDeleter( const SourceImageDeleter & originalCopy )
: refGraphicsRenderer( originalCopy.refGraphicsRenderer ) ,
ptrTextureID( originalCopy.ptrTextureID ) {};
void operator() ()
{
refGraphicsRenderer.deregisterTexture( ptrTextureID );
}
};
#endif
The RenderSystem::deregisterTexture function only requires one argument (unsigned int *), because of that, it's being passed at the creation of the functor. I've looked into the use of std::bind, but I don't have much experience with that and wasn't able to have much success using it instead of making a functor.
And here's the only method that uses it so far..
std::shared_ptr<SourceImage> Engine::createSourceImage( std::string tempFilepath )
{
SourceImage * tempImagePtr = new SourceImage( tempFilepath );
registerTexture( &tempImagePtr->textureID, &tempImagePtr->image );
return std::shared_ptr<SourceImage>( tempImagePtr , SourceImageDeleter( this->graphicsRenderer, &tempImagePtr->textureID ) );
}
I'm not sure why it's not working! I've basically been trying to have my smart_ptr run a custom deletion function all week, and between trying to figure out how pointers-to-method passing works, how std::bind/std::mem_fun_ref works, and how functors work has been stumping me all week..
Anyway, here's the compile error that Visual Studio has been giving me, I hope someone can help me figure out what I've been screwing up;
error C2064: term does not evaluate to a function taking 1 arguments
1> class does not define an 'operator()' or a user defined conversion operator to a pointer-to-function or reference-to-function that takes appropriate number of arguments
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\memory(1438) : see reference to function template instantiation 'void std::tr1::shared_ptr<_Ty>::_Resetp<_Ux,_Dx>(_Ux *,_Dx)' being compiled
1> with
1> [
1> _Ty=SourceImage,
1> _Ux=SourceImage,
1> _Dx=SourceImageDeleter
1> ]
1> c:\projects\source\engine.cpp(151) : see reference to function template instantiation 'std::tr1::shared_ptr<_Ty>::shared_ptr<SourceImage,SourceImageDeleter>(_Ux *,_Dx)' being compiled
1> with
1> [
1> _Ty=SourceImage,
1> _Ux=SourceImage,
1> _Dx=SourceImageDeleter
1> ]
(By the way, engine.cpp(151) is the return line inside Engine::createSourceImage shown above.. If I remove the deleter argument, the program compiles and runs fine aside from the obvious resource leaks associated with improper image deletion..)
std::shared_ptr passes in the pointer being deleted to the deleter, which is exactly what your error message says: the class does not define an operator() with the correct number of arguments.
Your deleter isn't expecting any parameters, so it won't work; you'll need to change it to void operator()(SourceImage*)
This is a simple and complex question at the same time.
This compiles:
int Test;
vector<int> TEST;
TEST.push_back(Test);
cout << TEST.size();
This does not compile:
fstream Test;
vector<fstream> TEST;
TEST.push_back(Test);
cout << TEST.size();
Is there any particular reason?
Is there a way for me to get a dynamic list of fstreams?
The error message:
1>------ Build started: Project: vector_test, Configuration: Debug Win32 ------
1> vector_test.cpp
1>c:\program files (x86)\microsoft visual studio 10.0\vc\include\fstream(1347): error C2248: 'std::basic_ios<_Elem,_Traits>::basic_ios' : cannot access private member declared in class 'std::basic_ios<_Elem,_Traits>'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\ios(176) : see declaration of 'std::basic_ios<_Elem,_Traits>::basic_ios'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> This diagnostic occurred in the compiler generated function 'std::basic_fstream<_Elem,_Traits>::basic_fstream(const std::basic_fstream<_Elem,_Traits> &)'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
The object fstream is not copyable.
If you need to record fstreams in a vector you can declare a std::vector<std::fstream*> and push back the address of the object. Remember that if you save the pointer, then you must ensure that, when you access it, the object is still alive.
In C++ 2011 the concrete stream objects are movable. Howver, to take advantage of this you either need to pass a temporary or allow the object to be moved:
std::vector<std::ofstream> files;
files.push_back(std::ofstream("f1"));
std::ofstream file("f2");
files.push_back(std::move(file));
Note that you can't use the file variable after this as the stream was moved into files.
To use a class with a vector, it must be copyable. fstream is not.
See: C++ std::ifstream in constructor problem
Edit: If you need to have multiple references to the same fstream, you can use shared_ptr to manage them. Try something like:
std::vector< std::shared_ptr<fstream> > TEST
A basic requirement for a type to be pushed into vector is that the object should be copyable, fstream is not copyable and hence you get compiler errors.
Like others have mentioned, fstream is not copyable. You could just do:
vector<fstream> TEST;
TEST.push_back(fstream()); //fstream is created in the vector, no copy needed
And use like this:
fstream& A = TEST[0];
And even iterate like this:
for(fstream& S : TEST){
...
}
sau_timer::sau_timer(int secs, timerparam f) : strnd(io),
t(io, boost::posix_time::seconds(secs))
{
assert(secs > 0);
this->f = f;
//t.async_wait(boost::bind(&sau_timer::exec, this, _1));
t.async_wait(strnd.wrap(boost::bind(&sau_timer::exec, this)));
boost::thread thrd(&io,this);
io.run();
//thrd(&sau_timer::start_timer);
}
This is the code I have in the constructor for the class 'sau_timer' (which will hopefully run a timer in a seperate thread and then call another function).
Unfortunately, atm when I try to compile, I get the following error:
1>c:\program files\boost\boost_1_39\boost\bind\bind.hpp(246) : error C2064: term does not evaluate to a function taking 1 arguments
Aswell as a whole bunch of warnings. What am I doing wrong? I've tried everything I can think of, thank you.
The explanation is at the end of the error messages:
c:\users\ben\documents\visual studio 2008\projects\sauria\sauria\sau_timer.cpp(11) :
see reference to function template instantiation
'boost::thread::thread<boost::asio::io_service*,sau_timer*>(F,A1)' being compiled
The error occurs while generating the ctor of boost::thread. It expects a function object (something with an opererator()()), and you pass it what (I guess) is an io::service. If what you want is a thread calling io_service::run, write:
boost::thread thrd(boost::bind(&io_service::run, &io));
If you use a relatively recent version of Boost, I believe that thread's ctor has a convenience overload that takes care of the bind(), allowing to simply write:
boost::thread thrd(&io_service::run, &io);
Each non-static member function has a first, hidden parameter - the instance on which function is to be called. So your exec function needs two arguments. And you have appropriate code, but it is commented out. I mean:
t.async_wait(boost::bind(&sau_timer::exec, this, _1));
Did you try it and had some other problems?
I need it to be used with strnd.wrap() aswell. I've changed it to this again:
sau_timer::sau_timer(int secs, timerparam f) : strnd(io),
t(io, boost::posix_time::seconds(secs))
{
assert(secs > 0);
this->f = f;
t.async_wait(strnd.wrap(boost::bind(&sau_timer::exec, this, _1)));
boost::thread thrd(&io);
io.run();
}
void sau_timer::exec(const boost::system::error_code&) { (f)(params); }
But now I get these errors:
1>------ Build started: Project: Sauria, Configuration: Debug Win32 ------
1>Compiling...
1>sau_timer.cpp
1>Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:
1>- add -D_WIN32_WINNT=0x0501 to the compiler command line; or
1>- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.
1>Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).
1>c:\program files\boost\boost_1_39\boost\bind\bind.hpp(246) : error C2064: term does not evaluate to a function taking 1 arguments
1> c:\program files\boost\boost_1_39\boost\bind\bind_template.hpp(20) : see reference to function template instantiation 'void boost::_bi::list1<A1>::operator ()<F,boost::_bi::list0>(boost::_bi::type<T>,F &,A &,int)' being compiled
1> with
1> [
1> A1=boost::_bi::value<sau_timer *>,
1> F=boost::asio::io_service *,
1> T=void,
1> A=boost::_bi::list0
1> ]
1> c:\program files\boost\boost_1_39\boost\bind\bind_template.hpp(18) : while compiling class template member function 'void boost::_bi::bind_t<R,F,L>::operator ()(void)'
1> with
1> [
1> R=void,
1> F=boost::asio::io_service *,
1> L=boost::_bi::list1<boost::_bi::value<sau_timer *>>
1> ]
1> c:\program files\boost\boost_1_39\boost\thread\detail\thread.hpp(227) : see reference to class template instantiation 'boost::_bi::bind_t<R,F,L>' being compiled
1> with
1> [
1> R=void,
1> F=boost::asio::io_service *,
1> L=boost::_bi::list1<boost::_bi::value<sau_timer *>>
1> ]
1> c:\users\ben\documents\visual studio 2008\projects\sauria\sauria\sau_timer.cpp(11) : see reference to function template instantiation 'boost::thread::thread<boost::asio::io_service*,sau_timer*>(F,A1)' being compiled
1> with
1> [
1> F=boost::asio::io_service *,
1> A1=sau_timer *
1> ]
1>Build log was saved at "file://c:\Users\Ben\Documents\Visual Studio 2008\Projects\Sauria\Sauria\Debug\BuildLog.htm"
1>Sauria - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========