This question already has answers here:
What's the difference between passing by reference vs. passing by value?
(18 answers)
Closed 6 years ago.
I'm reading this book and I'm having trouble understanding some of the code that's written in it. The program is supposed to function as a basic database for a company. It should have employee objects that contain their salary, status in company (hired/fired) and have some methods that you can call on that object to update it.
This is the code they provide
#pragma once
#include <string>
namespace Records {
const int kDefaultStartingSalary = 30000;
class Employee
{
public:
Employee();
void promote(int raiseAmount = 1000);
void demote(int demeritAmount = 1000);
void hire(); // Hires or rehires the employee
void fire(); // Dismisses the employee
void display() const;// Outputs employee info to console
// Getters and setters
void setFirstName(const std::string& firstName);
const std::string& getFirstName() const;
void setLastName(const std::string& lastName);
const std::string& getLastName() const;
void setEmployeeNumber(int employeeNumber);
int getEmployeeNumber() const;
void setSalary(int newSalary);
int getSalary() const;
bool getIsHired() const;
private:
std::string mFirstName;
std::string mLastName;
int mEmployeeNumber;
int mSalary;
bool mHired;
};
}
I can't seem to understand why on the setFirstName and setLastName they are passing in by reference in the parameters, then in other setters/getters (like setSalary) they are passing by value. If someone could explain why this is good practice, that'd be excellent! They didn't explain their choice in the book.
Passing by reference means you don't have to make a copy of the data in memory, just for the function call, since you're only sending the address of it, so you're using the original data (that's also why you might want to make it a const reference). For a simple variable, it doesn't really matter in the sense of performance, but with larger objects, it's faster to avoid having to make a copy of it.
A basic assumption to start with is that it's a good idea to use references for object, and values for variables. But in some cases, it really depends on a lot of other things. For example, if the function is going to do a lot of heavy calcuation, and you've got a reference to some object, which might be anywhere in memory, then you might get cache misses that will cost you performance. So there are a lot of possible things to consider for different situations. But a priori, the rule.of.thumb to use references for objects and by-value for variables is an overall good approach.
Related
Is there empty std::string defined somewhere?
What I mean is following:
I can do:
// code #1
int process(const char *s = nullptr);
// later I can use:
process();
However, if I do:
// code #2
int process(const std::string &s = "");
// later I can use:
process(); // wait, an object is created...
It compiles and works, when I use the function, there is unneeded object creation.
Is there standard way to do following:
// code #3
const std::string EMPTY_STR;
int process(const std::string &s = EMPTY_STR);
// later I can use:
process(); // fine, no object is created...
This is not bottleneck, nor it is a premature optimization.
I believe C++ is not Java, so right way is not to create objects that you do not need.
Also I believe code 3 looks much better than code 2 and also it show the intention that string is empty (and probably will not be used), than code 2, where is not very clear why the string is "".
There's no (safe) way of making a reference refer to nothing. If you don't want an object to be created at all, you have to use a pointer;
int process(const std::string *s = nullptr);
If you want to use references, there must be an object somewhere. For that purpose, you could use a default-constructed (empty) string as default argument;
int process(const std::string& s = std::string());
First of all, I am slightly surprised you need an OBJECT. It is going to be a const object anyway, so what does it give you which simple const char* does not?
Second, there is a solution to your problem in a generic way. There is a genuine problem with following omnipresent code:
void foo(const std::string& data);
It allows using foo with both std::strings and const char*, and suits almost everybody. It does not matter for majority of users of foo(), but for someone really fixed on performance (as in nanoseconds) creation of temporary std::string from their const char* is a sore point. To solve this problem, StringRef was invented. It is not available in std, but it exits in many libraries including boost, and is simple to implement. The idea is following:
class StringRef {
...
StringRef(const std::string& str) : b(str.begin()), end(str.end()) {}
StringRef(const char* str) : b(str), end(str + strlen(str)) {}
...
private:
const char* const b;
const char* const e;
};
void foo(const StringRef str);
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
A brother suggested me that I pass the arguments in the constructor and other member functions of the class by reference instead and even return references from member functions, so that it avoids copying of variables all the time. I'm a very naive programmer and don't know how best to do it. Can you please tell me how to apply it to the following program:
#include <iostream>
#include <string>
using namespace std;
class Student {
public:
Student(string s, int i) {
name = s;
id = i;
}
void setName(string s) {
name = s;
}
void setId(int i) {
id = i;
}
string getName() {
return name;
}
int returnId() {
return id;
}
private:
string name;
int id;
};
int main() {
Student s1("Seth",515);
}
This is what I did:
#include <iostream>
#include <string>
using namespace std;
class Student {
public:
Student(string& s, int& i) {
name = s;
id = i;
}
void setName(string& s) {
name = s;
}
void setId(int& i) {
id = i;
}
string& getName() {
return name;
}
int& returnId() {
return id;
}
private:
string name;
int id;
};
int main() {
string s = "John";
int i = 515;
Student s1(s,i);
return 0;
}
Is it alright to return reference variables, I mean don't they go out of scope in some cases?
I'm agree with Alexander completely: first, in your program it won't probably give you anything. Second, premature optimization is the root of all evil.
Still, if you're interested, in general passing a value by reference usually looks like this:
void myFunction(const MyComplicatedClass& argument) {...}
Here argument is passed as a reference to a constant object. This means that:
Instead of passing a value to the function, we pass a reference, so our function, when it accesses argument, will, in essence, work with the same region of memory as the function, that called myFunction. BUT if it works with the same region of memory, it can mess it up. So
We pass a reference to a constant object. It means, that the compiler will ensure, that we don't do anything, that can mess up the original object (which was passed to us asargument). It's not a 100% guarantee, we are talking about C++, it's relatively easy to shoot in the foot here, but the compiler will try his best :)
But it's important to understand, that there is no point in using this approach everywhere. For instance, there is no point in passing int value as a const reference, since it is a primitive type already. You might even make things less efficient. Many classes are implemented in a way, that makes copying a very cheap operation. And, finally, compilers nowadays are very smart. They can optimize out many things that you didn't think of.
Still, I don't say that this is useless. As with every tool, you should understand, how it works and when to use it. It comes with experience and studying.
As for returning a reference, never return a reference to local variables. They get deleted the moment they go out of scope, and your program will crash when you'll try to access a reference to a deleted content. You can, however, return references (const references) to anything, that you're sure will live long enough. For instance, class fields.
I am new to C++ and I am getting an error.
Basically I have a variable char myName[150] and have a method called
void setName(char myNames) {
this->myName = myNames;
}
My error is myName[150] is not equal to myNames. I think the compiler is trying to say incompatible types however I don't know how to fix my code.
Also, I'm interested in storing two sets of values, multiple times. For example, {[0,10], [5,15], [6,69]...} - would I be right in having something like this
int **d[]; /dynamic array - grows in size and not fixed
void setValues(int a, int b){
//NEED HELP WITH IMPLEMENTATION HERE
}
I would greatly appreciate it if someone could help me out with my errors and questions. I am very keen on learning this C++ language - I really like C++ and C, and wish I learnt them as my first ever programming language
The compiler is telling you that the types are different: myName is a char[150], but myNames is a char. That assignment doesn't work. Maybe you meant:
void setName(const char* name) {
strncpy(myName, name, sizeof(myName));
}
or
std::string myName;
void setName(const std::string& name) {
myName = name;
}
or some equivalent.
For the second question, just use std::vector<std::pair<int,int> >.
In the old days, you might have a function like this:
const char* find_response(const char* const id) const;
If the item could not be found, then a null could be returned to indicate the fact, otherwise obviously return the relevant string.
But when the function is changed to:
const std::string& find_response(const std::string& id) const;
What do you return to indicate item not found?
Or should signature really be:
bool find_response(const std::string& id, std::string& value) const;
What would be the most elegant modern C++ way?
boost::optional. It was specifically designed for this kind of situation.
Note, it will be included in upcoming C++14 standard as std::optional. Update: After reviewing national body comments to N3690, std::optional was voted out from C++14 working paper into a separate Technical Specification. It is not a part of the draft C++14 as of n3797.
Compared to std::unique_ptr, it avoids dynamic memory allocation, and expresses more clearly its purpose. std::unique_ptr is better for polymorphism (e.g. factory methods) and storing values in containers, however.
Usage example:
#include <string>
#include <boost/none.hpp>
#include <boost/optional.hpp>
class A
{
private:
std::string value;
public:
A(std::string s) : value(s) {}
boost::optional<std::string> find_response(const std::string& id) const
{
if(id == value)
return std::string("Found it!");
else
return boost::none;
//or
//return boost::make_optional(id == value, std::string("Found it!"));
}
//You can use boost::optional with references,
//but I'm unfamiliar with possible applications of this.
boost::optional<const std::string&> get_id() const
{
return value;
}
};
#include <iostream>
int main()
{
A a("42");
boost::optional<std::string> response = a.find_response("42"); //auto is handy
if(response)
{
std::cout << *response;
}
}
What would be the most elegant modern C++ way?
There's, as always, not just one solution to this problem.
If you decide to go for any solution that references the original resonse instance, you're on a slippery road when it comes to aliasing and memory management, especially in a multi threaded environment. By copying the response to the caller, no such issues arises.
Today, I would do this:
std::unique_ptr<std::string> find_response(const std::string& id) const;
That way, you can check for nullptr as "in the olden days" and it's 100% clear who's responsibility it is to clear up the returned instance: the caller.
The only downside I see of this, is the additional copy of the response string, but don't dismiss that as a downside until measured and proven so.
Another way is to do as is done when searching std::set<> and std::map<> - return a std::pair<bool, const char*> where one value is bool is_found and the other is const char* response. That way you don't get the "overhead" of the additional response copy, only of the returned std::pair<> which is likely to be maximally optimized by the compiler.
If the function is returning a string by reference, but needs the ability to indicate that no such string exists, the most obvious solution is to return a pointer, which is basically a reference that can be null, i.e. exactly what was sought after.
const std::string* find_response(const std::string& id) const;
There are several good solutions here already. But for the sake of completeness I'd like to add this one. If you don't want to rely on boost::optional you may easily implement your own class like
class SearchResult
{
SearchResult(std::string stringFound, bool isValid = true)
: m_stringFound(stringFound),
m_isResultValid(isValid)
{ }
const std::string &getString() const { return m_stringFound; }
bool isValid() const { return m_isResultValid; }
private:
std::string m_stringFound;
bool m_isResultValid;
};
Obviously your method signature looks like this then
const SearchResult& find_response(const std::string& id) const;
But basically that's the same as the boost solution.
Use of pointers in C++ is forgiven if you need to return a nullable entity. This is widely accepted.
But of course bool find_response(const std::string& id, std::string& value) const; is quite verbose. So it is a matter of your choice.
I think the second way is better. Or you can write like this:
int find_response(const std::string& id, std::string& value) const;
if this function return -1, it tells that you don't find the response.
I'm new to and learning C++. I know a fair amount of Java and some C.
What I want to do is to create an immutable name class that takes in a string value, copies that string to a class field and then eventually hashes it to an ID that can be parsed much more efficiently than a string.
I'm hitting a wall due to a general lack of knowledge of C++ strings. Here's what I have so far...
#pragma once
#include <string>
class Name
{
public:
Name(std::string s);
~Name(void);
int getId();
std::string getName();
private:
int id;
std::string name;
};
and...
#include "Name.h"
Name::Name(std::string s)
{
}
So what I want to do is store the value of s, passed in by the constructor in the "name" private field. As far as I know a new string object must be created and then the value of s must be copied into it.
I also think that the argument s can and should be a string pointer instead of a string object (to prevent an unnecessary copy from occurring). If I'm right then the constructor should look like the following, right?
Name::Name(std::string &s) { ... }
In this case, nothing would need to be done special when passing in a name? IE.
Name n = new Name("Cody");
is perfectly valid? Actually I'm not sure since "Cody" to my knowledge is a constant string or something like that.
So if I'm all on the right track, then what is the proper way to actually copy the value? I'm thinking this is appropriate but I'm not sure.
#include "Name.h"
Name::Name(std::string s)
{
name = new string(s);
}
Thanks for the help in advance, I know it's a basic question but I'm slowly making baby steps into the C++ world. :) - Cody
You are close, your code can be like this after a little massage:
class Name
{
public:
Name(const std::string& s); // add const and reference
~Name(void);
int getId() cosnt; // add const
std::string getName() const; // add const
private:
int id;
std::string name;
};
Name.cpp
Name::Name(const std::string& s):name(s)
{
}
Here :name(s) is called member initializer list.
Name n = new Name("Cody"); is perfectly valid? Actually I'm not sure
since "Cody" to my knowledge is a constant string or something like
that.
No, n is not pointer, it's not like java you need to new for every object. In C++, you do
Name n("Cody");
This will call Name(const std::string& s) to initialize object n and initialize name string with "Cody".
Note: variable n has automatic storage duration, it will be destroyed if it goes out of scope.
To let n on dynamic storage duration, you need to use new/delete pair:
Name *pn = new Name("Cody");
delete pn;
or use smart pointers, you no need to call delete n_ptr; as n_ptr will be destroyed when it goes out of scope as well:
#include <memory>
std::shared_ptr<Name> n_ptr(new Name("Cody"));
EDIT:
To use Name class in other classes, it's the same way when you use string in Name class, you don't have to use pointers.
class TestName
{
public:
TestName(const Name& n):name_(n){ }
private:
Name name_;
};
TestName tn("Cody");
You should use a constant reference to std::string here.
As you said, it would prevent unnecessary copies.. But then why not just a pointer or a constant pointer?
A constant reference would allow you to pass to your function some arguments that would implicitly call the right std::string constructor.
So, in a nutshell, you could do that:
Name::Name(const std::string& s)
{
this->name = s;
}
// Or even better..
Name::Name(const std::string& s):
name(s)
{
}
int main(void)
{
Name nick("hello");
return 0;
}
You can find out about every std::string's constructors on its cplusplus.com's sheet.