I'm trying to understand a Function/Method in a Library in order to port it to Java however some parameters don't make any sense to me and reading the source code the library is based on is not helping.
Function (Note the API has few comments (We can also ignore the calc handle since it's got a supplier method))
Ssr calc_ssr(CalcHandle *calc, NoteInfo *rows, size_t num_rows, float music_rate, float score_goal) {
std::vector<NoteInfo> note_info(rows, rows + num_rows);
auto skillsets = MinaSDCalc(
note_info,
music_rate,
score_goal,
reinterpret_cast<Calc*>(calc)
);
return skillset_vector_to_ssr(skillsets);
}
NoteInfo Struct
struct NoteInfo
{
unsigned int notes;
float rowTime;
};
MinaSDCalc
// Function to generate SSR rating
auto
MinaSDCalc(const std::vector<NoteInfo>& NoteInfo,
const float musicrate,
const float goal,
Calc* calc) -> std::vector<float>
{
if (NoteInfo.size() <= 1) {
return dimples_the_all_zero_output;
}
calc->ssr = true;
calc->debugmode = false;
return calc->CalcMain(NoteInfo, musicrate, min(goal, ssr_goal_cap));
}
Calc expected input file data (Only care about the #Notes: ...)
Pastebin
Question
What is NoteInfo in calc_ssr, I don't know any C or C++ so the *rows to me just seems like a pointer to a Noteinfo instance, however the MinaSDCalc methods requires an Array/Vector which using a pointer to a single instance doesn't make sense to me (pairing this with the fact that NoteInfo needs another parameter rowTime which I think is time of Note occurrence in the file which means that value must not be constant otherwise the produced result would be inaccurate)
Github Project: https://github.com/kangalioo/minacalc-standalone (The code alone may not explain enough but it's worth a try; best to look at API.h and discern what's used from there. Though I do warn you a lot of the Code is esoteric)
Sorry if this doesn't make much sense but I've been looking into this since June/July and this API is the closest abstraction from the bare C++ code I could find.
NoteInfo * rows here is pass by pointer. So, rows actually is a pointer to an instance of type NoteInfo. This is one of the ways to pass arrays in c++ to a function. Since arrays are contiguous in memory so we can just increment the pointer by one and get the next element of the array.
for example look at these three ways to do exactly one thing, parameter to pass an array to a function :-
1. void myFunction(int *param) {}
2. void myFunction(int param[10]) {}
3. void myFunction(int param[]) {}
Look into this link for more understanding : https://www.tutorialspoint.com/cplusplus/cpp_passing_arrays_to_functions.htm
Also search for pass by pointer and pass by reference to look into different ways of passing arguments in c++.
2.however the MinaSDCalc methods requires an Array/Vector which using a pointer to a single instance doesn't make sense to me: as to this question of yours, you can now see MinaSDCalc is actually getting an array and not a single instance as passing the pointer is also one of the ways of passing an array in c++.
I'm working on building a watch based on the Arduino/ATMega. The primary goal for now is to switch between "modes” (different functions) by pressing a button on the side. Initially, I had a long if statement like this:
if (counter == 0)
mode1();
enter code
else if (counter == 1)
mode2();
.... Repeat....
But that seems inefficient. So, I tried to make an array of the functions without actually calling them, and then call the indexed function later. The code segment is as follows (Apologies for the mess, it’s very much a WIP)
int Modes[3] = {showTime,flashlight,antiAnxiety} //these are all void functions that are defined earlier.
int scroller(){
int counter = 0;
int timeLeft = millis()+5000;
while (timer <= millis()){
...more code...
}
Modes[counter]();
}
However, when I try to compile that, I get an error:
Error: expression cannot be used as a function.
That logic works in Python, so I’m assuming there’s a concept I don’t know that gets abstracted away in higher-level languages. I’m quite willing to learn it, I just need to know what it is.
The type is wrong - instead of int you need void (*)() as type (because you have an array of void someFunction() function pointers, not an array of integers - and while the former can be converted to the latter in a way, as memory address, you cannot call an integer).
void (*Modes[3])() = {showTime, flashlight, antiAnxiety};
This code becomes easier to understand with a type definition:
typedef void (*func_type)();
func_type Modes[3] = {showTime, flashlight, antiAnxiety};
I am currently in a code optimization phase and I would need help: I have a large number of functions taking as parameters std::strings and in which these std::strings are transformed in doubles using std::stod. I would like to be able to create a "gateway" function that would allow all the parameters of the function to be changed at once. I had thought of a function using variadic templates. Can you help me, please? This is an example of one of my functions:
std::optional<d> rectangle(const std::string& length, const std::string& width) {
if (others::is_type<double>(length) && others::is_type<double>(width)) {
d length_ = stod(length);
d width_ = stod(width);
return std::round((length_ * width_) * options::rounder) / options::rounder;
}
return {};
}
If you want me to add more details or to detail the other functions used in this one, ask me in comments. I already thank the all of you who'll answer.
To answer the first comment : the gateway function would collect the parameters of an other function (I don't know how for the moment), verify that they are strings and then to convert them to double. The aim would be to be able to just use this function and not to write "double ... = stod(...)" all the time (cause I have a really big number of functions).
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I want a maintainable array/list of possible functions/behaviors, each representing another mode of operation, and I want to change the 'mode' simply by changing a variable storing the pointer to the right function. With researching I found the fact, that function-pointers are a bit smelly, but I wonder if
Ait is okay in my usecase to use them anyway
Bthere is a better/professional option.
Some pseudocode to show my prefered way of using it:
// store references to the modes and an information about the active mode
void * allModePointers[3];
int modeNumber = 2;
// call the active mode
(*allModePointers[modeNumber])();
void* is quite liberal with what type it accepts. By using it you give up compile time type checking. It is also hard to understand without typedef void* ModeFunctionPtr.
To get type checking and avoid pointer casting, you need a properly declared function pointer array like void(*allModePointers[3])() (verified by cdecl.org). This only works when the function signatures match, and if they don't, you are doing something wrong.
In the end, I would recommend std::function, which is a wrapper for callable objects. It has the advantage of being able to accept lambda expression, and works well with other std functions like std::bind if you one day find that static functions are not enough.
Short answer: When using C++ the most professional way to implement behaviors that do not readily exist in a library is to use a class.
Specific advice: if I understand your intent correctly, you want to model something like a terminal (i.e. performs a task based on a command). What I would do is make a class that only has functions (I have done this before to model a calculator) and maybe some static constants thrown in if you need them. One of the functions will be a control function that just takes in the command and calls one of the other functions based on that command, then returns the answer. Throw it in a .h, make it look neat with Doxygen and voila! You have your maintainable list of behaviors. I will demonstrate below using my calculator example. The one I made was to do vector calc, but I will make a simple one that only adds and squares.
/* doxygen comments */
/* include guards, includes, etc, etc */
class Calculator{
public:
/* static constants if needed (i.e. pi, e, ...) */
/* constructor, destructor, getters if you want to make the
constants private */
/* doxygen comments */
double run( int function_id, double x, double y ){
switch( function_id ){
case 0: return add( x, y );
case 1: return square( x );
default: return x; //why not?
}
}
private:
/* doxygen comments */
inline double square( double x ) { return x*x; }
/* doxygen comments */
inline double add( double x, double y ) { return x+y; }
};
Although this example is a little different than mine because I actually just made all the functions public and called them myself from main. Anyway, you get the gist, but there's probably less memory expensive ways of doing it as well.
I am now working on a rather complex project involving control of a simulated robotic arm.
I finished a first version of the project and it is working fine.
I just added some new code that collect some information about the system at each iteration, save it in some arrays, and at the end prints everything in a file for later analysis.
Now, something real strange is happening. If I define the file in which the data will be saved as follow:
const std::string SAVEFILE = "C:\\Users\\Vincent\\Desktop\\ta";
everything works fine, exactly the same as it did before I add the new code (plus saving the data).
But if I define it as follow:
const std::string SAVEFILE = "C:\\Users\\Vincent\\Desktop\\tacit.txt";
then the system behaves in another way. Does not crash, but the robotic arm moves differently.
I tried to comment all the code that was making use of SAVEFILE, and even any new code related to data saving, but the problem persists.
I know that with only this information, it is unlikely that anybody can tell me what is wrong, but would anybody have some advice what direction to look ?
Would it make sense to think that a long string overwrite the value of some other variable ? How can it be possible ? Some guideline of clean C++ programming I might have broken ?
That some array is misbehaving sounds possible, and was the first thing I checked. I guess it should come from the arrays saving data, as they are the only new one. Thing is, even when I comment all the corresponding code, no change.
I try to give more information about my code. Here where I first use SAVEFILE (last argument of the runExperiment function)
int main(int argc, char *argv[]) {
std::vector<Controller*> controllers;
controllers.push_back(getConstrainedPDT(0,true));
controllers.push_back(getConstrainedPDT(1,true));
controllers.push_back(getConstrainedPDT(2,true));
runExperiment(controllers,LENGTHS,WEIGHTS,RADIUS,ANGLEMIN,ANGLEMAX,MAXTORQUES,PUSHVECTOR,GRAVITY,RUNTIME,TIMESTEP,XTARGET,YTARGET,ITERATIONSAVEDATA,SAVEFILE);
return 1;
}
and here the code of the function:
void runExperiment(std::vector<Controller*> controllers,const double * lengths, const double* weights, const double radius, const double* angleMin, const double* angleMax, const double* maxTorques,const double* pushVector,const dReal gravity,const dReal runTime,const dReal tstep,const dReal targetX,const dReal targetY,const int itSaveData,const std::string saveFile){
endTime = runTime;
simTime = 0.0;
timeStep = tstep;
dInitODE();
world = dWorldCreate();
space = dHashSpaceCreate(0);
contactgroup = dJointGroupCreate(0);
ground = dCreatePlane(space, 0, 0, 1, 0);
dWorldSetGravity(world, 0, 0, gravity);
createTargetObject(targetX,targetY);
int nbData = static_cast<int>( ( endTime / timeStep ) / static_cast<double>(itSaveData) );
robot = new R2DRobot(&world,controllers.size(),lengths,weights,radius,angleMin,angleMax,maxTorques,pushVector,controllers,itSaveData,nbData);
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &setViewPoint;
fn.step = &loop;
fn.stop = &stopSim;
fn.path_to_textures = PATH_TO_TEXTURES;
dsSimulationLoop(0, 0, 1280, 960, &fn);
dWorldDestroy(world);
dCloseODE();
// NOTE: commenting the next three lines does not fix the problem !
// it is the only place saveFile is used, except in the code of printData
// I do not show the code of printData as commenting it does not change anything
if (itSaveData>0){
robot->printData(saveFile);
}
delete robot;
}
In the hope to find the unspecified variable (not that easy for a project with a lot of classes, some of them virtual), I played with the const parameters and observed the behavior of the robot. I reached a situation:
works fine all the time:
const std::string SAVEFILE = "C:\\Users\\Vincent\\Desktop\\tacit.txt";
crashes the program:
const std::string SAVEFILE = "C:\\Users\\Vincent\\Desktop\\ta";
Now the issue is, if I add a single line to the code of runExperiment (call to printf added):
printf("experiment.cpp - 1 \n");
robot = new R2DRobot(&world,controllers.size(),lengths,weights,radius,angleMin,angleMax,maxTorques,pushVector,controllers,itSaveData,nbData);
then both versions of SAVEFILE work fine and do give exactly similar results.
Now, if I delete the call to printf and add in the constructor of R2DRobot:
R2DRobot::R2DRobot(dWorldID * world, const int nbLinks, const double * lengths, const double * weights, const double radius,const double* angleMin,const double* angleMax,const double* maxTorques,const double* pushVector, std::vector<Controller*> controllers,int saveData,int nbData):
Robot(3*nbLinks+3,controllers),pushVector(pushVector),nbLinks(nbLinks),weights(weights),angleMin(angleMin),angleMax(angleMax),maxTorques(maxTorques),itSaveData(saveData){
printf("experiment.cpp - 1 \n");
// rest of the code
then the program crashes (if using the short version of SAVEFILE) but after printing "experiment.cpp -1" in the console.
Same thing if I move the call to printf to the constructor of Robot, the mother class of R2DRobot.
This might be manifestation that your program does not initialize variables properly. When string was shorter, compiler created certain memory layout, and variables created on a stack (or on a heap) had certain values. By pure luck, those values were something that seemed to work right for you.
Now, since string has become longer, compiler has changed memory layout a little, and this led to slightly different layout. Now, these uninitialized variables might have slightly different values. It does not necessarily crash, but works differently.
but would anybody have some advice what direction to look
This information is really not enough, unfortunately. Maybe, you can try using valgrind or a similar tool to analyze your code.
Would it make sense to think that a long string overwrite the value of some other variable? How can it be possible?
No, this is not a long string. It's not even close to long string. If the string is too long, you'll have an exception for invalid length.
Some guideline of clean C++ programming I might have broken
Not enough information. Using std::string is good and it's even recommended.
The problem is somewhere else. Sounds like undefined behavior to me.
The height number of arguments to runExperiment with are global variables are telling you that you may need a higher level object to wrap and organize it. While trying to write a constructor for such an object you will probably see and correct the problem with the incorrect/un-initialized variables, with will prevent undefined behavior.