I have an assignment (see below for question) for a beginners c++ class, where i am asked to pass 2 values back from a single function. I am pretty sure of my understanding of how to use functions and the general structure of what the program should be, but i am having trouble fingin how to pass two variables back to "main" from the function.
Assignment:
Write a program that simulates an airplane race. The program will display a table showing the speed in km/hour and distance in km traveled by two airplanes every second until one of them has gone 10 kilometers.
These are the requirements for the program:
-The program will use a function that has the following parameters: time and acceleration.
-The function will pass back two data items: speed and distance.
You have two options (well, three really, but I'm leaving pointers out).
Take references to output arguments and assign them within the function.
Return a data structure which contains all of the return values.
Which option is best depends on your program. If this is a one off function that isn't called from many places then you may chose to use option #1. I assume by "speed" you mean the "constant velocity" which is reached after "time" of acceleration.
void calc_velocity_profile(double accel_time,
double acceleration,
double &out_velocity, // these last two are
double &out_distance); // assigned in the function
If this is a more general purpose function and/or a function which will be called by many clients I would probably prefer option #2.
struct velocity_profile {
double velocity;
double distance;
};
velocity_profile calc_velocity_profile(double accel_time, double acceleration);
Everything being equal, I prefer option 1. Given the choice, I like a function which returns a value instead of a function which mutates its input.
2017 Update: This is discussed in the C++ Core Guidelines :
F.21 To return multiple "out" values, prefer returning a tuple or struct
However, I would lean towards returning a struct over a tuple due to named, order-independent access that is encapsulated and reusable as a explicit strong type.
In the special case of returning a bool and a T, where the T is only filled if the bool is true , consider returning a std::optional<T>. See this CPPCon17 video for an extended discussion.
Struct version:
struct SpeedInfo{
float speed;
float distance;
};
SpeedInfo getInfo()
{
SpeedInfo si;
si.speed = //...
si.distance = //...
return si;
}
The benefit of this is that you get an encapsulated type with named access.
Reference version:
void getInfo(float& speed, float& distance)
{
speed = //...
distance = //...
}
You have to pass in the output vars:
float s;
float d;
getInfo(s, d);
Pointer version:
void getInfo(float* speed, float* distance)
{
if(speed)
{
*speed = //...
}
if(distance)
{
*distance= //...
}
}
Pass the memory address of the output variable:
float s;
float d;
getInfo(&s, &d);
Pointer version is interesting because you can just pass a nullptr/NULL/0 for things you aren't interested in; this can become useful when you are using such a function that potentially takes a lot of params, but are not interested in all the output values. e.g:
float d;
getInfo(nullptr, &d);
This is something which you cant do with references, although they are safer.
There is already such a data structure in C++ that is named as std::pair. It is declared in header <utility>. So the function could look the following way
std::pair<int, int> func( int time, int acceleration )
{
// some calculations
std::pair<int, int> ret_value;
ret_value.first = speed_value;
ret_value.second = distance_value;
return ( ret_value );
}
Related
Say my member function needs to return both a std::vector<std::pair<MyClass,double>> and a double. Both are computed as part of the same algorithm: I need them both returned from the same member function. (I.e. I cannot have two separate functions easily; it would require duplicate code and performance overhead.)
I read that it is better to avoid out parameters in these quidelines, i.e.:
F.20: For "out" output values, prefer return values to output
parameters.
So my code looks as follow:
std::pair<std::vector<std::pair<MyClass,double>>,double>
computeTransitionsAndCost(double input);
(A std::pair<MyClass,double> is a transition, hence the name.)
With out parameter, this would be
std::vector<std::pair<MyClass,double>> computeTransitions(double input, double& costOut);
In the latter code, it is clearer to the user what the function returns: a list of pairs. But the guidelines are against it, because
A return value is self-documenting, whereas a & could be either in-out or out-only and is liable to be misused.
Is there any way to adhere to the guidelines and still ensure that it is clear to the user of the code what is represented by the return values?
Why not return a composite like follows?
struct ComputedTransitions
{
struct Transition
{
MyClass description;
double weight;
};
std::vector<Transition> transitions;
double cost;
};
ComputedTransitions computeTransitions(double input);
This will let you both give meaningful names to the elements of the return value, and put all the related data into one structure.
In c++
I'm running an optimization algorithm to find a set of parameters for a given combination of temperature and humidity and I want a structure for efficient look-up and iteration time for further computation.
Example: I calculate all 5-parameters for a device across the range of Temperature[0k-300k] x Humidity[x-xxx]. I want to store these in memory and when I call a function at a given temperature and humidity, it should be able to quickly load the relevant 5 parameters using the tuple as a key.
I'm thinking of a multimap such as std::multimap<double, std::vector<double>>, but I'm iffy about the baggage that comes with vector.
Edit:
Ok an example will be like this (for one variable):
for x in range(Temperature){
parameterList[x] = (deviceClass.geneticAlgo(loss = 1, x));
deviceClass.setParameters(parameterList);
Then for that class I want:
double later_calc(temperature,humidity, x...){
return deviceSimulation(parameterList[(temperature, humidity, x...)]);
}
I want the later_calc function to quickly access the structure in the class accessed by the input of temperature, humidity, etc.
It seems to me you want to use a std::map with either a std::tuple as key or a custom class which holds the parameters, and a mapped type which stores the experiment result (here it is double, but you can also easily use a custom Result class):
struct ParameterType
{
int temperature;
int humidity;
int x;
bool operator<(ParameterType const& rhs) const
{
return std::tie(temperature, humidity, x) < std::tie(rhs.temperature, rhs.humidity, rhs.x);
}
};
using ResultType = double;
int main()
{
std::map<ParameterType, ResultType> params;
params[{263, 10, 1}] = 1.0;
std::cout<< params[{263, 10, 1}] <<std::endl;
}
DEMO
You should use a multimap if you want to repeat experiments, i.e. if you have multiple results for the same parameter set. (But you could also use a map with a std::vector<ResultType>).
Note that I've used integer values as a key, whereas in practice one is tempted to use floating point numbers. Those, however, might lead to problems in key comparison due to rounding errors. So better fix the decimal digits and decode real inputs as 263.53 as 26353.
I'm new to programming and I'm studying the C++ programming language using the book : Programming principles and practice using C++. I'm here today because at the end of chapter 8, the author focuses on functions and proposes an exercise to invite the learner to think about the better solution to a problem :
Write a function that finds the smallest and the largest element of a vector argument and also computes the mean and the median. Do not use global variables. Either return a struct containing the results or pass them back through reference arguments. Which of the two was of returning several values do you prefer and why ?
Now, usually I wouldn't define a single function to perform several actions but in this case I have to create just one function and think about how to return several values. My first approach was to create a function that takes reference arguments like this :
void my_func(
vector<double>& numbers,
double& min,
double& max,
double& mean,
double& median
);
But going on with writing the program I started to think that this solution used too many arguments and maybe the other solution proposed (using struct) would be better. How would you use a struct to solve this problem ? How do you return several values from a function ?
Using struct for this problem is simple: define a struct for the return type, and use it, like this:
struct stats {
double min;
double max;
double mean;
double median;
};
stats my_func(vector<double>& numbers) {
stats res;
...
res.min = ...
res.max = ...
res.mean = ...
res.median = ...
return res;
}
The tradeoff here is that in exchange for having a much simpler function signature, the users of your function need to extract the elements that they want one by one.
But what about if the struct is really complex and the cost of copying becomes too expensive?
It takes a structure of extreme size for copying to become too expensive in comparison to the "payload" CPU time of your function. On top of that, C++ optimizer reduces the copying costs by employing copy elision and return value optimization strategies when you do this:
stats s = my_func(numbers);
When the struct becomes so gigantic that you don't want to copy it, combine the two approaches like this:
void my_func(vector<double>& numbers, stats& res);
Declare the struct
i.e.
struct stats {
double min;
double max;
double mean;
double median;
};
Then
stats my_func(vector<double>& numbers);
The function will be like this
stats my_func(vector<double>& numbers) {
stats return_value;
// Fill in the structure
return return_value;
}
Well you just return a struct.
struct res {
double min;
double max;
double mean;
double median;
};
res my_func(vector<double>& numbers) {
res result;
// do stuff, put result in in result.min etc
return result;
}
The other can be done in a similar way:
void my_func(vector<double>& numbers,
res& result)
{
// the same code except no return value
return;
}
Now for the question in your task (which I shall not answer - because it's a question what you prefer) I'd like to mention what the technical difference is.
When returning a struct it means you will possibly create a temporary copy of the result struct (it may also result in two objects res one for the caller and one for my_func to work with). While the other approach means that you pass to the function essentially addresses where to put the result. With a "good" implementation you may end up with the same code.
I have been getting this error come up in the for loop when I try to assign values to x_dev, y_dev, and pearson. As far as I can see they should all be modifiable. Can anyone see where I have gone wrong?
class LoopBody
{
double *const x_data;
double *const y_data;
double const x_mean;
double const y_mean;
double x_dev;
double y_dev;
double pearson;
public:
LoopBody(double *x, double *y, double xmean, double ymean, double xdev, double ydev, double pear)
: x_data(x), y_data(y), x_mean(xmean), y_mean(ymean), x_dev(xdev), y_dev(ydev), pearson(pear) {}
void operator() (const blocked_range<size_t> &r) const {
for(size_t i = r.begin(); i != r.end(); i++)
{
double x_temp = x_data[i] - x_mean;
double y_temp = y_data[i] - y_mean;
x_dev += x_temp * x_temp;
y_dev += y_temp * y_temp;
pearson += x_temp * y_temp;
}
}
};
Having followed #Bathsheba 's advice I have overcome these problems. However When running a parallel_for the operator is runs but the for loop is never entered.
This is where I call the parallel_for:
parallel_for(blocked_range<size_t>(0,n), LoopBody(x, y, x_mean, y_mean, x_dev, y_dev, pearson), auto_partitioner());
The () operator is marked const, and you're attempting to modify class member data (e.g. x_dev, y_dev and person). That is not allowed and is why you're getting the compile-time error.
You probably want to drop the const from the method.
Alternatively you can mark the member data that you want to modify as mutable, but this is not the preferred solution as it makes code brittle, difficult to read and can wreak havoc with multi-threading.
Seemingly you want to do reduction, i.e. compute some aggregate values over the data.
For that, TBB offers a special function template: parallel_reduce. Unlike parallel_for that perhaps you use now, parallel_reduce does not require operator() of a body class to be const, because an instance of that class accumulates partial results. However, it poses other requirements to the class: the need to have a special constructor as well as a method to merge partial results from another body instance.
More information can be found in the Intel(R) TBB User Guide: http://www.threadingbuildingblocks.org/docs/help/tbb_userguide/parallel_reduce.htm
Also there is an overload of parallel_reduce which takes two functors - one for body and another one for merging partial results - as well as a special "identity" value used to initialize accumulators. But you are computing three aggregate values at once, so you would still need to have a struct or class to store all three values in a single variable.
I'm currently implementing some algorithms into an existing program. Long story short, I created a new class, "Adder". An Adder is a member of another class representing the physical object actually doing the calculus , which calls adder.calc() with its parameters (merely a list of objects to do the maths on).
To do these maths, I need some parameters, which do not exist outside of the class (but can be set, see below). They're neither config parameters nor members of other classes. These parameters are D1 and D2, distances, and three arrays of fixed size: alpha, beta, delta.
I know some of you are more comfortable reading code than reading text so here you go:
class Adder
{
public:
Adder();
virtual Adder::~Adder();
void set( float d1, float d2 );
void set( float d1, float d2, int alpha[N_MAX], int beta[N_MAX], int delta[N_MAX] );
// Snipped prototypes
float calc( List& ... );
// ...
inline float get_d1() { return d1_ ;};
inline float get_d2() { return d2_ ;};
private:
float d1_;
float d2_;
int alpha_[N_MAX]; // A #define N_MAX is done elsewhere
int beta_[N_MAX];
int delta_[N_MAX];
};
Since this object is used as a member of another class, it is declared in a *.h:
private:
Adder adder_;
By doing that, I couldn't initialize the arrays (alpha/beta/delta) directly in the constructor ( int T[3] = { 1, 2, 3 }; ), without having to iterate throughout the three arrays. I thought of putting them in static const, but I don't think that's the proper way of solving such problems.
My second guess was to use the constructor to initialize the arrays:
Adder::Adder()
{
int alpha[N_MAX] = { 0, -60, -120, 180, 120, 60 };
int beta[N_MAX] = { 0, 0, 0, 0, 0, 0 };
int delta[N_MAX] = { 0, 0, 180, 180, 180, 0 };
set( 2.5, 0, alpha, beta, delta );
}
void Adder::set( float d1, float d2 ) {
if (d1 > 0)
d1_ = d1;
if (d2 > 0)
d2_ = d2;
}
void Adder::set( float d1, float d2, int alpha[N_MAX], int beta[N_MAX], int delta[N_MAX] ) {
set( d1, d2 );
for (int i = 0; i < N_MAX; ++i) {
alpha_[i] = alpha[i];
beta_[i] = beta[i];
delta_[i] = delta[i];
}
}
Would it be better to use another function (init()) which would initialize the arrays? Or is there a better way of doing that?
Did you see some mistakes or bad practice along the way?
You have chosen a very wide subject, so here is a broader answer.
Be aware of your surroundings
Too often I have seen code doing the same thing as elsewhere in the codebase. Make sure that the problem you are trying to solve has not already been solved by your team-mates or predecessors.
Try not to reinvent the wheel
An extension of my previous point.
While everyone should probably write a linked-list or a string class as an exercise, there is no need to write one for production code. You will have access to MFC, OWL, STL, Boost, whatever. If the wheel has already been invented, use it and get on with coding a solution to the real problem!
Think about how you are going to test your code
Test Driven Development (TDD) is one way (but not the only way) to ensure that your code is both testable and tested. If you think about testing your code from the beginning, it will be very easy to test. Then test it!
Write SOLID code
The Wikipedia page explains this far better than I could.
Ensure your code is readable
Meaningful identifiers are just the beginning. Unnecessary comments can also detract from readability as can long functions, functions with long argument lists (such as your second setter), etcetera. If you have coding standards, stick to them.
Use const more
My major gripe with C++ is that things aren't const by default! In your example, your getters should be declared const and your setters should have their arguments passed in as const (and const-reference for the arrays).
Ensure your code is maintainable
Unit tests (as mentioned above) will ensure that the next person to change your code doesn't break your implementation.
Ensure your library is usable
If you follow Principle of least astonishment and document your library with unit-tests, programmers using it will have fewer issues.
Refactor mercilessly
An extension of the previous point. Do everything you can to reduce code duplication. Today I witnessed a bug-fix that had to be executed in fifteen separate places (and was only executed in thirteen of these).
When creating an object I would advise to always give the user an complete object, with all member properly initialized. An Init method fails in doing that, making room for a common error, failing to calling the initializing function in a two phase initialization object. To prevent this either make your constructor private and use a builder function or a factory which in turn has access to the init method, or make init private and use it in the constructor. The last advice is generally the same as doing the initialization in the constructor, but it allows several constructors to use the same initializing action.
Okay.
I would:
Set the arrays to a known state by
using memset to clear all values to
0 (or some other value) within the
constructor before they are used.
Change the constructor to allow the
passing of array pointers that can
be used to initialise the arrays to
some other values.
Retain the Set
function that you have to change the
values within the arrays and
ariables that you're using.
Don't use virtual functions, unless your design actually requires them.
In a class that exists primarily to execute one function, that function is canonically named operator(). I.e. you'd call yours as adder_(params), not adder_.calc(params).
If you're initializing three arrays, it's more efficient to use three for-loops. (cache friendly)