Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Volguus
Mar 3, 2009
Here is some sample code: http://codepad.org/TOTixB1a
Same code is pasted here if you don't want to click:
code:
struct ShapeInterface
{
 virtual void Draw()=0;
 virtual void SetName(char* name)=0;
 virtual char* GetName()=0;
};
struct CircleInterface:public ShapeInterface
{
  virtual void SetRadius(double radius)=0;  
};
class ShapeImpl:public ShapeInterface
{
  virtual void SetName(char* name){/*save it somewhere*/}
  virtual char* GetName(){/*return it*/ return NULL;}
};
class CircleImpl:public CircleInterface,public ShapeImpl
{
 virtual void Draw(){/*draw a circle*/}
 virtual void SetRadius(double radius){/*set the radius*/}
};

int main()
{
 CircleImpl circle;
 return 0;
}
As it can be seen, the code tries to define 2 interfaces, and 2 implementations of those interfaces.
CircleInterface extends ShapeInterface, and CircleImpl extends ShapeImpl (while also implementing CircleInterface).
The error that the compiler throws is: cannot declare variable 'circle' to be of abstract type 'CircleImpl'.

My problem is with the 2 SetName/GetName methods. They are defined in ShapeInterface, and implemented in ShapeImpl.
However, it seems like I have to implement them in CircleImpl as well (even if they are just calling ShapeImpl::SetName()/ShapeImpl::GetName()).

Am I doing something wrong, or this is the way it's supposed to happen in C++.
Coming from Java, this construct (extend A implement B) is perfectly valid and I do not have to implement any methods that A defines that are implemented in B.

Can it be done in C++ too? Or will I just have to live with it?

Adbot
ADBOT LOVES YOU

Volguus
Mar 3, 2009

Avenging Dentist posted:

Use virtual inheritance: http://codepad.org/Q21fhVP1

Thank you sir.

Volguus
Mar 3, 2009
From what I can see, you appear to be using these in an awkward way. Normally the code would look like this:
C++ code:
void Semaphore::Signal() {
	cond.notify_one();
}
void Semaphore::Wait() {
	boost::unique_lock<boost::mutex> lock(mut);
	cond.wait(lock);
}
Now, when you want to wait, you call Wait(). Then when you want to wake up this thread, from a different thread you call Signal() (both threads have the same Semaphore object).
If you want to do this from both sides, use 2 semaphores. One thread only calls Wait() on semaphore1 and signals on semaphore2 and the other thread signals semaphore1 and waits on semaphore2.
Of course, the fun part comes when both threads wait, and neither can signal each other :).

Volguus
Mar 3, 2009

Boz0r posted:

I'm supposed to use SIMD and SSE to to optimize runtime of a raytrace renderer. I can't seem to find much info on how to use this in Visual Studio. Does anyone have any good resources for this?

Are you referring to this http://en.wikipedia.org/wiki/Streaming_SIMD_Extensions ?
Because these are just ... instructions. You can write them by hand or use a library. Maybe this would be helpful: http://stackoverflow.com/questions/61341/is-there-a-way-to-insert-assembly-code-into-c

Volguus
Mar 3, 2009

Vanadium posted:

This seems really complicated to get right, I think I am going to jump ship into the -fno-rtti -fno-exceptions camp.

I found this boostcon video to be extremely educative: https://www.youtube.com/watch?v=N9bR0ztmmEQ

Personally I believe that writing exception-safe code is not that hard, and that it is worth it. There are way too few cases where disabling exceptions makes sense, and too many benefits of using them.

Volguus
Mar 3, 2009
Has anyone ever used libunrar (from https://github.com/vilkov/libunrar)?

I have the following code:

code:
extractor_service::extract_status unrar_extractor_service::extract(const boost::filesystem::path& destination, 
				 const std::set< boost::filesystem::path >& files, 
				 std::set< boost::filesystem::path >& extractedFiles)
{
  modif_string dest_str(destination.c_str(),destination.string().length());
  Logger logger = Logger::getInstance("log");
  for(auto& file : files )
  {
    RAROpenArchiveDataEx rarData = {0};    
    modif_string str(file.c_str(),file.string().length());
    rarData.ArcName = str.str();
    rarData.OpenMode = RAR_OM_EXTRACT;    
    HANDLE archive = RAROpenArchiveEx(&rarData);
    if(rarData.OpenResult != 0) {
      RARCloseArchive(archive);
      continue;
    }
    //RARSetCallback(archive,RARCallbackProc,0);
      RARHeaderDataEx rarHeader;
      if(RARReadHeaderEx(archive,&rarHeader) != 0) {
	continue;
      }      
      
      if(RARProcessFile(archive,  RAR_EXTRACT, dest_str.str() , NULL) != 0)
      {
	LOG4CPLUS_ERROR(logger, "Cannot extract "<<file.string());
      }
      else
      {
	LOG4CPLUS_INFO(logger, "Successfully extracted "<<file.string());
      }
      

    RARCloseArchive(archive);
  }
  return extractor_service::extrOK;
}
where modif_string is a struct like this (shouldnt matter in this context):
code:
struct modif_string {
  modif_string(const char* str, size_t len):value(new char[len+1]){ 
    memset(value, 0, len+1);
    if(str && len>0) {
      strncpy(value,str,len);
    }
    
  }
  char* str() const {
    return value; 
  }
  ~modif_string(){    
    delete []value;    
  }
private:
  char* value;
};
As it can be seen, I am passing to the function a set of files and a destination directory. I am expecting back the list of files that were extracted (the set of files will contain text files, pictures, junk, and hopefully some rar files).
Now, when I call this function with a simple rar file everything is fine and the file is extracted in the specified directory.
When I call this function on a multi-volume archive, I get something like this:
pre:
 Cannot extract /tmp/test/test.r00
 Cannot extract /tmp/test/test.r01
 Cannot extract /tmp/test/test.r02
 Cannot extract /tmp/test/test.r03
 Successfully extracted /tmp/test/test.rar
But there's nothing in the destination folder. I tried with a callback function, without, and everything i could think of. What would I need to do to be able to extract a multi-volume rar archive?

Thank you.

Edit:
Im using gcc (GCC) 4.8.1 20130603 (Red Hat 4.8.1-1) on Fedora 19 if that matters.

Volguus fucked around with this message at 02:17 on Aug 13, 2013

Volguus
Mar 3, 2009
There are a lot of open source programs out there (7z for example) that can and do uncompress rar files. Won't create them, but can extract them. I'll go study them to see how do they do it, but I was kinda hoping for some obvious mistake that I'm doing that will let me extract multi volume archives without too much fuss. The unrar binary is quite convoluted.

Volguus
Mar 3, 2009

Gazpacho posted:

Why do you want to check the byte order? If you need to encode and decode integers in a standard format, Unix systems already have functions for that.

In embedded development you may. If you get a board from some strange vendor that has a chip with few K of ram and runs like is being powered by hungry hamsters, chances are that you won't have access to endian.h .
At which point you will have to write your own test routine. What I found on stackoverflow looks like a good approach, though there may be simpler ones out there: http://stackoverflow.com/questions/2100331/c-macro-definition-to-determine-big-endian-or-little-endian-machine

Volguus
Mar 3, 2009
Here's a talk from Alexandrescu where he shows a manual vtable implementation in one of the slides, which apparently is faster than the gcc generated one (the entire talk is very interesting in and of itself): http://channel9.msdn.com/Events/GoingNative/2013/Writing-Quick-Code-in-Cpp-Quickly?video

Volguus
Mar 3, 2009

pr0metheus posted:

What is the best resource for studying C++11 features? I am familiar with older specification (C++03), but need to big up on the new things.

Don't know if it's the best one, but this is a quite nice cheat sheet: http://isocpp.org/blog/2012/12/c11-a-cheat-sheet-alex-sinyakov

Volguus
Mar 3, 2009

more like dICK posted:

AI've got an class that owns a std::vector<Foo>. A Foo can be in one of two states, up or down. Foos are big and don't like being copied. Clients of this class only care about getting a sequence of Foos that are up, so I'd like to provide a view over the vector. Is something like a forward_list<reference_wrapper<Foo>> the best way to provide this? Assuming here that the class will add and remove Foo references to the list as they change state. Does a list of reference_wrappers offer any advantage over a list of pointers?

shared_ptr's could help you here.

Volguus
Mar 3, 2009

Rusty Kettle posted:

I have a bunch of programs that generate x,y,z coordinates in an iterative way for an infinite amount of time, and a program that displays the x,y,z coordinates in a pretty visualization.

The bunch of generators are all independent and run on their own hardware/software stack. The visualization program I would like to keep separate. I need an interface that will send the x,y, and z coordinates to the display.

My solution right now is to have the programs write the coordinates to binary, then have the visualization program running concurrently watching the generated binary for updates. If it updates, pull the data and display. This seems dumb. There has to be a better way to pipe the coordinates from the generator to the display.

Another way could be using actors. libcppa is one library that provides an actor system implementation.

Volguus
Mar 3, 2009

bobua posted:

Idea check:

I'm controlling some cameras, and I need to be careful about only accessing them from a single thread. To do this, I came up with a function that just loops through and checks variables(with the appropriate mutexes) and that loop\thread handles all communication with the cameras. So another thread stores what to do in a variable, then the camera loop thread does it on the next round.


Details aside, is there a better\standard way that I should be handling this situation?

Why not look at active objects? It looks like it's the thing you're looking for: http://herbsutter.com/2010/07/12/effective-concurrency-prefer-using-active-objects-instead-of-naked-threads/

For the message queue i used a simple sync queue implementation. You can probably find better ones: http://pastebin.com/ghVeC68f

Volguus fucked around with this message at 03:59 on Dec 3, 2013

Volguus
Mar 3, 2009

Dren posted:

I can't seem to find the project settings I need in KDevelop. It couldn't find the includes it needed so it prompted me to edit the custom include path, which I did, but now I can't get back to that menu.

I like the stuff I have figured out much better than Eclipse.

The best thing about KDevelop is that you don't need project settings. Everything you need is in the CMakeLists.txt file. You add include folders there, linking libraries, etc.

Volguus
Mar 3, 2009

Tetraptous posted:

Interesting! So does this mean that if I have an existing CMake project, I can just point KDevelop at it and it'll just work?

I usually just use Emacs, but the various semantic/autocompletion modes always seem limited or hard to set up. KDevelop looks interesting, if it's not too much effort to try. Can I configure it to use Emacs key bindings in the editor?

Yes, it should "just work". As for Emacs mode, i don't know if it supports that (or what exactly this mode would mean to you), but you can configure the shortcuts.

Another decent IDE is QT Creator (which also supports CMake files, among other things). Version 2.8.1 found in Fedora 20 is actually surprisingly nice. I tried it some few years back and it sucked, but now i am actually using it for a week and all is fine and dandy.

Volguus
Mar 3, 2009
For C# to native C++ you would have to go through C++/CLI (the .net c++). That is, you would have your c# code, that gets the file that has been opened, which would call a method in c++/cli with the .net string, which will convert that .net string to std::string (or const char* or whatever) which will call your library.

No idea about Obj-C but something can be done in there as well.

If you want to go web app route, you can use an already made framework such as cppcms, which will allow you to run locally, natively, and be a web server at the same time. And apparently it can be compiled to work on all the platforms (and you solved the cross-platform ui problem).

Volguus
Mar 3, 2009

movax posted:

Ah, client-side JS/HTML5? (I am not a web-app guy at all) So the source would be exposed on their side right?

I'm looking around for resources re: cross-platform development, and got a decent set of rules here so far, still looking around for more resources & examples.

On the other hand, what would the js/html5 code do? render certain things. the guts of the problem could still be hidden away on the server side (native c++ app). unless of course, the entire thingy is just the view, in which case minify, minify, minify. 3 times the charm.

Volguus
Mar 3, 2009

Rocko Bonaparte posted:

So assuming I have a shared pointer as a member, in the initialization it would be... my_shared_ptr(make_shared<bla>(whatever))?

std::shared_ptr<bla> my_shared_ptr = std::make_shared<bla>(params);

Volguus
Mar 3, 2009

Subjunctive posted:

Well Andrei obviously does.

Andrei just bragged not too long ago about pushing the first D program in production at facebook: http://forum.dlang.org/thread/l37h5s$2gd8$1@digitalmars.com

Volguus fucked around with this message at 23:06 on Mar 28, 2014

Volguus
Mar 3, 2009
You were using exception for control flow. Don't do that. It is a well known anti-pattern. Exceptions should be used for exceptional situations, not to break from a loop. Essentially, this usage is no better than a goto.

Here's a stackexchange thread that may be more helpful: http://programmers.stackexchange.com/questions/189222/are-exceptions-as-control-flow-considered-a-serious-antipattern-if-so-why

Volguus
Mar 3, 2009

Plorkyeran posted:

That you're using std::stoi is very relevant, and makes that code reasonable IMO specifically because you're reusing the error handling that you need anyway, unlike if it was std::strtol where the throw and catch would be pointlessly roundabout.

std:stoi throws std::out_of_range if the value falls out of the range of the type. Here maxAllowedValue is the business rule regarding that type. There are two very different things. Yes he needs that try/catch, but the catch is only for when the user enters a value that cannot be represented by an int. For when the user enters a reasonable int value, but that violates the business rules (maxAllowedValue) he should either throw his own exception so that somebody up the chain can handle that (show the user the error message for example) or just return like he does in his out_of_range catch.

Throwing an std::out_of_range because the user entered value 20 (if maxAllowedValue is 15 for example) is just control flow. It shouldn't be a habit to catch on.

Volguus
Mar 3, 2009

Plorkyeran posted:

I get that much, and I can buy the argument that using std::out_of_range for business logic violations is incorrect because it's for precondition violations, but I don't understand how throwing one type of exception is using exceptions for control flow but throwing another type isn't (or is acceptable control flow).

Because you wouldn't (shoudlnt) catch your exception in the try/catch. That one is meant for whoever is calling you. In my opinion, the code would be better with something like this:

code:
try
{
    inputInt = std::strtoi(input);
    if (inputInt > maxAllowedValue)
    {
        throw invalid_input_exception("The value is not acceptable. Max acceptable value is "+std::to_string(maxAllowedValue));
    }
}
catch (std::out_of_range)
{
   throw invalid_input_exception("The value is not acceptable. Please enter a value between 0 and "+std::to_string(maxAllowedValue));
}
Then the caller can catch invalid_input_exception and do something (shouldn't show the message of an exception to the user, should be something more user friendly, but that's not relevant for this discussion), such as warn the user.
The cause of that exception is not really relevant to the caller, so it shouldn't be burdened with that.

Why is this better than just throwing std::out_of_range? Because tomorrow you may change the code, to convert a string to int using some other algorithm. One that doesn't throw std::out_of_range. Or maybe you will do some other black magic inside your function. By only telling your caller that the only thing he has to worry about is invalid_output_exception, you are now free to do whatever you want in your function, use whatever algorithm you want and just make sure that you throw that exception if you dont like the input (for whatever reason). A change in the business rules should only be your problem, not the caller's.

Volguus
Mar 3, 2009

Plorkyeran posted:

The fact that some std::out_of_range are coming directly from your function and some happen to be bubbling out is an implementation detail that the caller does not need to be aware of. If you need to change to a different string parsing method that signals errors in a different way, then you just have to throw std::out_of_range whenever the new string parsing method signals that the value is out of range. Choosing an interface which simplifies your implementation does not mean that your interface has to change to keep your implementation simple, and in this case your implementation after changing would be identical to what it would have been if you prematurely pessimized by translating std::out_of_range (other than the name of the exception being thrown, obviously).

But if the business rules change so that the input is invalid for some other reason (mars, earth and the sun are in alignment for example) then throwing out_of_range is kinda ... wrong, isn't it? The input is invalid. Why? Why do you care? It's invalid and that's that.

The input doesn't have to be "out of range" to be invalid, that's my entire point. Hiding that implementation detail from the caller is, in my opinion, good design practice.
Then again, probably in most real world cases this may not matter, no matter what you throw out (if anything, just returning may be just fine). Of course, in cases where good design practices have a performance penalty ... then screw good design. But usually, it pays in the long run.

Volguus
Mar 3, 2009

Plorkyeran posted:

The obvious case is that you want to show different error messages for different problems, and having the error message controlled by the UI rather than the layer throwing the error. It's much easier to throw away excess detail about what exactly went wrong than to go the other direction. Wanting all of your validation exceptions to have a common base class to simplify that would be a good reason for mapping std::out_of_range to a different exception type, but I don't have any idea what that has to do with the idea that throwing std::out_of_range is using exceptions for control flow and throwing some other exception is not.

It all has to do with how it's handled. Throwing out_of_range from your function exposes an implementation detail (may or may not be ok, usually is not). Throwing exception within a try and catching it later (rethrowing it or just returning doesnt matter) it is just a simple control flow problem. Why? You can use a simple return if you want to exit the function cleanly. You can use a boolean variable if you want to check for success later. You have 100 other mechanisms available to accomplish the same thing without going into exceptions.
There are quite a few examples given at http://c2.com/cgi/wiki?DontUseExceptionsForFlowControl .
However, in C++ land, one must be worried about performance as well: https://www.youtube.com/watch?v=N9bR0ztmmEQ.

The links provided hopefully can explain better than I can. If not, don't worry, for most cases it's probably not a huge issue.

Volguus
Mar 3, 2009

Hammerite posted:

I feel like this argument is kind of going over my head. I don't really understand the whole discussion about passing information about failure back to the caller. As I said to astr0man on the previous page, the point of the function in which the relevant code appeared (at least, the point of the function as I originally intended it) was that it would test the user's input, decide whether it was valid, and either display a "friendly" error message explaining what was wrong (if it was not valid) or execute the requested operation by delegating to other functions (it it was valid). By design, the main loop of the program doesn't need to know which of those it was. It just repeatedly delivers lines of input to this function, it doesn't care what they mean or whether they worked.

code:
Main loop in main(): "while (!menuHandler.IsQuitting()) {/* do stuff */}"
         |
         |
         |
         v
Input parse method (where the code in question appears)
         |
         |
         |
         v
 Further functions

In which case then, a simple return from the if statement would do, just like you're doing from the catch.

Volguus
Mar 3, 2009

Optimus Prime Ribs posted:

The problem was what MutantBlue pointed out (i.e. me accidentally starting the thread twice), but what difference would putting the function's definition below main make? Wouldn't the compiled program be the exact same?

It would. For 100 lines programs there is no difference in readability/maintainability regardless of the coding practices employed. Variable names as a,b and c are perfectly fine. goto's all over the place are perfectly fine.
However, after you've been working for a while on very large projects, you start to realize that readability is the most important part. Everything else is a distant second. Optimizations, bug fixing, adding new features become trivial (usually) if the code itself is readable, follows conventions, is essentially clean.

Saying "But i will follow the rules once i get a job" doesn't usually work. You will have to meet deadlines, you will work under pressure. If the habit is not formed to keep the code clean by then, you will have a hard time adjusting.

Volguus
Mar 3, 2009

From the looks of it, something like a key/value database would help. Have you looked at Redis? Or MongoDB (though that's a document store, but it may be just what you need)? Both have C apis. I am not 100% sure about querying though.

Volguus
Mar 3, 2009

FateFree posted:

I am successfully using this code to execute a hash. However my next step is trying to return the result to a java application via JNI. The method signature looks like this, but I can't figure out how to convert the output array to a jbytearray. Here is what I tried after seeing some examples:

code:
JNIEXPORT jbyteArray JNICALL Java_com_fatefree_WNative_getSHA256Bytes(JNIEnv * env, jobject jobj, jstring jstr) {
	const char * input = (*env)->GetStringUTFChars(env, jstr, 0);
	uint32_t output[8];
	sha256_hash(input, strlen(input), output);
	
	// Need help with this part - how to correctly convert the output array to a jbytearray?
	jbyte* buf = new jbyte[size];
	memset (buf, output, size);
	jbyteArray ret = env->NewByteArray(size);
	env->SetByteArrayRegion (ret, 0, size, buf);
	delete[] buf;
	return ret;
}	

First of all, there are plenty of pure java libraries out there that can calculate sha-256 from a string.
But, for the sake of argument, let's assume that you have to (somehow) use JNI, and that function specifically (sha256_hash). Apparently, that function is giving you a uint32_t array. Now, each element of that array is (duh) a uint32_t, that is an unsigned 4 bytes integer. You cannot (normally) convert that to a byte array, since each byte is , well, 1 byte, not 4 (well, you can cast it if you really want, but then you're endianess dependent, it's more headache than it's worth. plus ... who's gonna delete it? The Java gc won't know about it).
You cannot even use a java int, since int in java is a 32-bit signed two's complement integer. Long would be the least you can do. And you most likely cannot just write memset, but instead go through each element of the array and assign the value to the other array (longArray[i] = output[i]). Or, maybe memcpy could work somehow, but it such a freaking pain.

My advice would be to just go to a java library that does that for you. If you're worried about performance, then Java is not the right language to write your program in. Use plain C or C++.

Volguus
Mar 3, 2009

FateFree posted:

Thanks for the insight. I'm aware of the java libraries but this is more of a JNI exercise that I can verify against the java libraries. But I am also trying to maximize performance. I think just to get it working I'll pass back a hex string to java and then i won't need to worry about these data types. Qwerty gave me a print loop which displays the correct hex, so I'd like to try to append that to a string and return it as the result of the method. Can I utilize the printf function somehow, since it seems so compact? Here is what he gave me:

code:
for (i = 0; i < 8; i++)
{
    printf("%08X", output[i]);
}

You could use sprintf on a char array, and put that into a string. Something like:
code:
char *buf = (char*)malloc(255);
for (i = 0; i < 8; i++)
{
    char tmp[10];
    sprintf(tmp,"%08X", output[i]);
    strcat(buf, tmp);
}
jstring jstrBuf = (*env)->NewStringUTF(env, buf);
Or maybe using std::stringstream would be easier (formatting can be specified with fill and width : stream << std::setfill('0') << std::setw(2) << value;)

Volguus
Mar 3, 2009

epalm posted:

Here's probably a stupid C++ question!

I have a char buf[1000], and buf is filled with n chars by some other means (received some data via socket). I also have a fancy std::stringsteam resp here. How do I get the contents of buf into resp? Other than

C++ code:
for (int i = 0; i < n; i++) {
    resp << buf[i];
}
Or is that The Right Way?

Just doing resp << buf seems to copy all 1000 characters (the first n plus 1000-n of nonsense (uninitialized memory, presumably)).

vvv thanks!

std::stringstream.str(buf) should work. But, ensure that you initialize buf to all 0's before doing the copy.
Or make a std::string from that buf, where you can specify the length:
code:
 std::string s(buf, n);
 std::stringstream ss;
 ss.str(s);

Volguus
Mar 3, 2009

Newf posted:

I'm looking to drop a real simple webserver into a windows application - it only has to respond to GET requests and will have to serve a page that it generates from some of its own internal state.

Any suggestions for something ready made?

Microsoft has made an open source C++ REST SDK that may be able to help: https://casablanca.codeplex.com/

Volguus
Mar 3, 2009

Since i can't sleep, i came up with this inefficient abomination O(n*n). Seems to work though:

code:
void printsorted(node* root) {
    string min = "";
    string cur_min = "";
    node* temp = root;
    
    while (temp) {
        min = "";

        while (temp) {
            if (min.empty() && cur_min.empty()) { //our first time here??
                min = temp->str; 
            }
            else
            if ((min.empty() && temp->str > cur_min) 
                || (min > temp->str && temp->str > cur_min)) {
                min = temp->str;
            }
            temp = temp->next;
        }
        cur_min = min;
        cout << cur_min << endl;
        if (min.empty()) break;

        temp = root;
    } 
}
The only important part in here is that second if statement:
code:
  if ((min.empty() && temp->str > cur_min) 
                || (min > temp->str && temp->str > cur_min))
Which reads as:
If min hasn't been assigned yet and the current value is greater than the current running minimum OR min is greater than the current value and the current value is greater than the current running minimum, set min to the current value.

Essentially it looks for the smallest value that's greater than the current running minimum (which is the greatest minimum found so far). But is not efficient speed wise. Simpler to just sort the drat thing using one of the many available sorting algorithms.

Volguus
Mar 3, 2009
I have a question about a little piece of code that I'm writing:
I have a base_controller class with a bunch of controllers that extend base_controller and override a bunch of methods in base. When a request comes in I dispatch the request to one of the appropriate controllers that I have registered for that particular request (I have a std::unordered_map<std::string,std::unique_ptr<base_controller>> that keeps track of which is which).
The dispatch methods are all virtual overridden from the base_controller.
Now, the dispatch methods ... are all the same, the difference only being the method that will get called in the corresponding controller. In order to write less code, I came up with this :

C++ code:
template <typename Callable>
bool api_controller::call_sub_controller(Callable&& cb,const Request& request, Response& response)
{
  auto identifier = get_controller_identifier(request); 
  auto controller = sub_controllers.find(identifier);
  bool found = (controller != sub_controllers.end());
  if( found )
  {
    auto new_req = request;
    new_req.uri = get_controller_uri(request);
    ((controller->second.get())->*cb)(new_req,response); //here I call the overridden method of whatever controller has been registered for that identifier
  }
  return found;
}

//and I call it like this
void api_controller::method1(const Request& request, Response& response)
{
  if(!call_sub_controller(&base_controller::method1,request,response)) // here I dispatch to the appropriate sub controller, and if I cannot find one, call the base class
  {
    base_controller::method1(request,response);    
  }
}

This works. Took me a bit to find out the correct syntax, but it works.
But now I have method2 which has 3 parameters, but otherwise is the same as method1: api_controller::method2(const Request& request, Response& response, const std::vector< char >& body).
Is there a way that I can modify call_sub_controller to work for both?
I tried with variadic templates, but the call to the subcontroller ... went nowhere. That is, the program didn't crash, but it was like the call was not getting made, even though it reached ((controller->second.get())->*cb) line.

Here's what I tried:
C++ code:
template <typename Callable,typename Req,typename...Arguments>
bool api_controller::call_sub_controller(Callable&& cb,const Req& request, Arguments....params)
{
//code as  before...
    ((controller->second.get())->*cb)(new_req,params);
//....
}
//and I call it as before
Question 1: Is there a way to accomplish my goal (not have 2 methods with identical bodies, except for 1 little line) and not use a macro?
Question 2: From the above code, all of the dispatch methods look like this:
C++ code:
void api_controller::method1(const Request& request, Response& response)
{
  if(!call_sub_controller(&base_controller::method1,request,response)) // here I dispatch to the appropriate sub controller, and if I cannot find one, call the base class
  {
    base_controller::method1(request,response);
  }
}
Can the code in the template function be modified so that the base class method1 is called if found == false? Something like this produces a stack-overflow, because is of course calling the method1 is api_controller instead of the class:
C++ code:
template <typename Callable>
void api_controller::call_sub_controller(Callable&& cb,const Request& request, Response& response)
{
  auto ident = get_controller_identifier(request);
  auto controller = sub_controllers.find(ident);
  bool found = (controller != sub_controllers.end());
  if( found )
  {
    auto new_req = request;
    new_req.uri = get_controller_uri(request);
    ((controller->second.get())->*cb)(new_req,response);
  }
  else
  {
	(this->*cb)(request,response);
  }
}
Thank you.

Edit: I am using Fedora 23 with gcc (GCC) 5.3.1 20151207 (Red Hat 5.3.1-2) with -std=c++14

Volguus fucked around with this message at 14:45 on Feb 9, 2016

Volguus
Mar 3, 2009

eth0.n posted:

Possible solution ....

Thank you.
That's what I get for typing things from memory on a topic that I never used before, such as variadic templates. My code was compilable of course, just not working. Been reading in the last few days Meyer's Effective Modern C++ (11 and 14), and unfortunately I still cannot understand universal references and perfect forwarding. Either Scott is not explaining well or i'm just thick. Or both.
It "looks" to be a relatively easy topic but, ugh ... I'll have to study harder I guess.

Anyway, thanks for the pointers. Haven't thought about ODR violations, I'll fix and try again asap.

Edit: This indeed solved my problem. Thank you.

Volguus fucked around with this message at 00:57 on Feb 11, 2016

Volguus
Mar 3, 2009
I've recently heard about http://nanapro.org/en-us/ . It's modern C++ (not C) but from the examples it looks quite decent. It doesn't seem to be just a wrapper over GTK or other libraries, it looks like it does its own painting.

Volguus
Mar 3, 2009

roomforthetuna posted:

Sure, but don't use new either if you don't know what you're doing. That's even worse because you're introducing memory leaks when you neglect to clean up, whereas with placement new at least you're only leaking sub-objects. :)

Placement new is really no harder to handle than regular new, it just has less support in unique_ptr etc. and you're less likely to know about it because it doesn't tend to get taught. But if it did get taught, it isn't any harder to understand placement new + call the destructor than it is to understand new and delete.

(To be fair, when I mentioned this earlier I did have to look up unique_ptr to see if it's possible to scope-destruct things you placement-new'd - it is, but not trivial. I think you could fairly easily make a unique_placement_ptr template that would handle it correctly.)

What would you suggest to do when dealing with a C API that accepts a struct as a parameter, and that struct has a "void* user_data" member? And then you need that user_data later on, when you're far away from the original scope when the struct was created and initialized?
Making an unique_ptr live that long would require quite a bit of refactoring plus not to mention leaking the API to the header and to whoever includes that. That can be solved with pimpl, but you are still left with the non-trivial refactoring problem.

Volguus
Mar 3, 2009

Ralith posted:

Sometimes refactoring is necessary to allow resource ownership to be explicitly encoded. Do it, preempt the otherwise nearly inevitable leaks, and try to plan ahead better next time.

I understand that and I agree ... usually ... but in this particular case the struct itself is the owner. What refactoring would do would destroy an otherwise very clean design with clearly defined boundaries. To leak that pointer outside the scope of the struct (in order to prolong its life) would essentially give ownership of that unique_ptr to a different entity who should not have any business in managing lifetime of those objects.
Essentially, from what I can see, I can either maintain the clean design, with the downside of having to do a new and later on a delete (all encapsulated in a higher order unique_ptr with a custom deleter, since ... that's life in C) or break the design only so that I don;t have to do new/delete.

Anyway, thanks for the input. Its been bugging me for a while that maybe I'm missing something, some better way.

Volguus
Mar 3, 2009

Ralith posted:

Well, who owns the struct? Is there anything stopping you from exposing a wrapped version of it with a destructor, move constructors, etc?
I own that struct. I control its lifespan.
I could wrap it I guess, it would be a solution. I just wrote a paragraph explaining my dilemma, removed it, I guess I better just show some code (changed to protect the innocent and my company from killing me. it's from memory anyway):

C++ code:
//c_header
struct C_struct
{
 int* pointer1; // some array of ints
 size_t pointer1_length;
 //other crap
 void* user_data;
};

int do_something_with_structs(C_struct** array_of_pointers, size_t length);


//my code
struct C_struct_array_deleter
{
//no idea if storing information in a deleter is kosher, but it's surely handy
size_t count;
C_struct_array_deleter(size_t count): count(count) {}
void operator()(C_struct** structs)
{
 for (size_t i = 0; i< count;++i)
 {
    C_struct* member = structs[i];
    delete[] member->pointer1;
    //here i delete user_data
    my_user_data* user_data = static_cast<my_user_data*>(member->user_data);
    delete user_data;
 }
 delete[] structs;
}
};

typedef std::unique_ptr<C_struct*[],C_struct_array_deleter> C_struct_array;

C_struct* create_struct(const unique_ptr<my_data>& some_data)
{
   C_struct* c_str = new C_struct;
   //other initizalization
   c_str->user_data = new my_user_data(some_numbers);
   return c_str;
}

C_struct_array create_struct_array(const std::vector<std::unique_ptr<my_data>>& data)
{
    std::vector<std::unique_ptr<my_data>> new_data = create_new_data_from_old_data(data); //this is actually a cartezian product done inside from the original data
    C_struct_array structs(new C_struct*[data.size()]{0},C_struct_array_deleter(data.size()));
    int index = 0;
    for(const auto& data_element : new_data)
    {
      structs[index] = create_struct(data_element,/*..and other params*/);
      index ++;      
    }
    return structs;
}


void now_my_actual_method_where_everything_gets_done(const std::vector<std::unique_ptr<my_data>>& data)
{
    //do things
    C_struct_array structs = create_struct_array(data);
    if(do_something_with_structs(structs.get(), structs.get_deleter().count))
   {
      throw my_exception("Something is rotten in Denmark");
    }

//etc, other things come here dealing with the structs created.

}

Now, looking again at it, hmm, there may be things that could be done I guess. Such as calling std::vector<std::unique_ptr<my_data>> new_data = create_new_data_from_old_data(data); in the main method and pass that to the create_struct_array, and then user_data could be just the value of my_data.get(). As it is though, the new_data vector has relatively short lifespan, which is nice.

Volguus fucked around with this message at 04:32 on Mar 9, 2016

Volguus
Mar 3, 2009

Xarn posted:

Because the whole thing is crazy ...
...

No, that's not crazy, that's loving insane.

Adbot
ADBOT LOVES YOU

Volguus
Mar 3, 2009

Joda posted:

I want to start developing commercial software, which means my educational license for CLion isn't really gonna cut it anymore. Before spending €99 a year on a commercial license, I thought I'd ask if there are any good, free alternatives that work on Windows, Linux and OSX? Preferably with CMake as the primary system for project management, and it has to work with MinGW, gcc and its standard library >=4.8.

QtCreator. Light years ahead of CLion. I personally prefer KDevelop on linux though (not sure if KDevelop works on other platforms).

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply