I have a Storage class that keeps a list of Things:
#include <iostream>
#include <list>
#include <functional>
class Thing {
private:
int id;
int value = 0;
static int nextId;
public:
Thing() { this->id = Thing::nextId++; };
int getId() const { return this->id; };
int getValue() const { return this->value; };
void add(int n) { this->value += n; };
};
int Thing::nextId = 1;
class Storage {
private:
std::list<std::reference_wrapper<Thing>> list;
public:
void add(Thing& thing) {
this->list.push_back(thing);
}
Thing& findById(int id) const {
for (std::list<std::reference_wrapper<Thing>>::const_iterator it = this->list.begin(); it != this->list.end(); ++it) {
if (it->get().getId() == id) return *it;
}
std::cout << "Not found!!\n";
exit(1);
}
};
I started with a simple std::list<Thing>, but then everything is copied around on insertion and retrieval, and I didn't want this because if I get a copy, altering it does not reflect on the original objects anymore. When looking for a solution to that, I found about std::reference_wrapper on this SO question, but now I have another problem.
Now to the code that uses them:
void temp(Storage& storage) {
storage.findById(2).add(1);
Thing t4; t4.add(50);
storage.add(t4);
std::cout << storage.findById(4).getValue() << "\n";
}
void run() {
Thing t1; t1.add(10);
Thing t2; t2.add(100);
Thing t3; t3.add(1000);
Storage storage;
storage.add(t3);
storage.add(t1);
storage.add(t2);
temp(storage);
t2.add(10000);
std::cout << storage.findById(2).getValue() << "\n";
std::cout << storage.findById(4).getValue() << "\n";
}
My main() simply calls run(). The output I get is:
50
10101
Not found!!
Although I was looking for:
50
10101
50
Question
Looks like the locally declared object t4 ceases to exist when the function returns, which makes sense. I could prevent this by dynamically allocating it, using new, but then I didn't want to manage memory manually...
How can I fix the code without removing the temp() function and without having to manage memory manually?
If I just use a std::list<Thing> as some suggested, surely the problem with t4 and temp will cease to exist, but another problem will arise: the code won't print 10101 anymore, for example. If I keep copying stuff around, I won't be able to alter the state of a stored object.
Who is the owner of the Thing in the Storage?
Your actual problem is ownership. Currently, your Storage does not really contain the Things but instead it is left to the user of the Storage to manage the lifetime of the objects you put inside it. This is very much against the philosophy of std containers. All standard C++ containers own the objects you put in them and the container manages their lifetime (eg you simply call v.resize(v.size()-2) on a vector and the last two elements get destroyed).
Why references?
You already found a way to make the container not own the actual objects (by using a reference_wrapper), but there is no reason to do so. Of a class called Storage I would expect it to hold objects not just references. Moreover, this opens the door to lots of nasty problems, including undefined behaviour. For example here:
void temp(Storage& storage) {
storage.findById(2).add(1);
Thing t4; t4.add(50);
storage.add(t4);
std::cout << storage.findById(4).getValue() << "\n";
}
you store a reference to t4 in the storage. The thing is: t4s lifetime is only till the end of that function and you end up with a dangling reference. You can store such a reference, but it isnt that usefull because you are basically not allowed to do anything with it.
Aren't references a cool thing?
Currently you can push t1, modify it, and then observe that changes on the thingy in Storage, this might be fine if you want to mimic Java, but in c++ we are used to containers making a copy when you push something (there are also methods to create the elements in place, in case you worry about some useless temporaries). And yes, of course, if you really want you can make a standard container also hold references, but lets make a small detour...
Who collects all that garbage?
Maybe it helps to consider that Java is garbage-collected while C++ has destructors. In Java you are used to references floating around till the garbage collector kicks in. In C++ you have to be super aware of the lifetime of your objects. This may sound bad, but acutally it turns out to be extremely usefull to have full control over the lifetime of objects.
Garbage? What garbage?
In modern C++ you shouldnt worry to forget a delete, but rather appreciate the advantages of having RAII. Acquiring resources on initialzation and knowing when a destructor gets called allows to get automatic resource management for basically any kind of resource, something a garbage collector can only dream of (think of files, database connections, etc.).
"How can I fix the code without removing the temp() function and without having to manage memory manually?"
A trick that helped me a lot is this: Whenever I find myself thinking I need to manage a resource manually I stop and ask "Can't someone else do the dirty stuff?". It is really extremely rare that I cannot find a standard container that does exactly what I need out of the box. In your case, just let the std::list do the "dirty" work.
Can't be C++ if there is no template, right?
I would actually suggest you to make Storage a template, along the line of:
template <typename T>
class Storage {
private:
std::list<T> list;
//....
Then
Storage<Thing> thing_storage;
Storage<int> int_storage;
are Storages containing Things and ints, respectively. In that way, if you ever feel like exprimenting with references or pointers you could still instantiate a Storage<reference_wrapper<int>>.
Did I miss something?...maybe references?
I won't be able to alter the state of a stored object
Given that the container owns the object you would rather let the user take a reference to the object in the container. For example with a vector that would be
auto t = std::vector<int>(10,0); // 10 element initialized to 0
auto& first_element = t[0]; // reference to first element
first_element = 5; // first_element is an alias for t[0]
std::cout << t[0]; // i dont want to spoil the fun part
To make this work with your Storage you just have to make findById return a reference. As a demo:
struct foo {
private:
int data;
public:
int& get_ref() { return data;}
const int& get_ref() const { return data;}
};
auto x = foo();
x.get_ref = 12;
TL;DR
How to avoid manual resource managment? Let someone else do it for you and call it automatic resource management :P
t4 is a temporary object that is destroyed at exit from temp() and what you store in storage becomes a dangling reference, causing UB.
It is not quite clear what you're trying to achieve, but if you want to keep the Storage class the same as it is, you should make sure that all the references stored into it are at least as long-lived as the storage itself. This you have discovered is one of the reasons STL containers keep their private copies of elements (others, probably less important, being—elimination of an extra indirection and a much better locality in some cases).
P.S. And please, can you stop writing those this-> and learn about initialization lists in constructors? >_<
In terms of what your code actually appears to be doing, you've definitely overcomplicated your code, by my estimation. Consider this code, which does all the same things your code does, but with far less boilerplate code and in a way that's far more safe for your uses:
#include<map>
#include<iostream>
int main() {
std::map<int, int> things;
int & t1 = things[1];
int & t2 = things[2];
int & t3 = things[3];
t1 = 10;
t2 = 100;
t3 = 1000;
t2++;
things[4] = 50;
std::cout << things.at(4) << std::endl;
t2 += 10000;
std::cout << things.at(2) << std::endl;
std::cout << things.at(4) << std::endl;
things.at(2) -= 75;
std::cout << things.at(2) << std::endl;
std::cout << t2 << std::endl;
}
//Output:
50
10101
50
10026
10026
Note that a few interesting things are happening here:
Because t2 is a reference, and insertion into the map doesn't invalidate references, t2 can be modified, and those modifications will be reflected in the map itself, and vise-versa.
things owns all the values that were inserted into it, and it will be cleaned up due to RAII, and the built-in behavior of std::map, and the broader C++ design principles it is obeying. There's no worry about objects not being cleaned up.
If you need to preserve the behavior where the id incrementing is handled automatically, independently from the end-programmer, we could consider this code instead:
#include<map>
#include<iostream>
int & insert(std::map<int, int> & things, int value) {
static int id = 1;
int & ret = things[id++] = value;
return ret;
}
int main() {
std::map<int, int> things;
int & t1 = insert(things, 10);
int & t2 = insert(things, 100);
int & t3 = insert(things, 1000);
t2++;
insert(things, 50);
std::cout << things.at(4) << std::endl;
t2 += 10000;
std::cout << things.at(2) << std::endl;
std::cout << things.at(4) << std::endl;
things.at(2) -= 75;
std::cout << things.at(2) << std::endl;
std::cout << t2 << std::endl;
}
//Output:
50
10101
50
10026
10026
These code snippets should give you a decent sense of how the language works, and what principles, possibly unfamiliar in the code I've written, that you need to learn about. My general recommendation is to find a good C++ resource for learning the basics of the language, and learn from that. Some good resources can be found here.
One last thing: if the use of Thing is critical to your code, because you need more data saved in the map, consider this instead:
#include<map>
#include<iostream>
#include<string>
//Only difference between struct and class is struct sets everything public by default
struct Thing {
int value;
double rate;
std::string name;
Thing() : Thing(0,0,"") {}
Thing(int value, double rate, std::string name) : value(value), rate(rate), name(std::move(name)) {}
};
int main() {
std::map<int, Thing> things;
Thing & t1 = things[1];
t1.value = 10;
t1.rate = 5.7;
t1.name = "First Object";
Thing & t2 = things[2];
t2.value = 15;
t2.rate = 17.99999;
t2.name = "Second Object";
t2.value++;
std::cout << things.at(2).value << std::endl;
t1.rate *= things.at(2).rate;
std::cout << things.at(1).rate << std::endl;
std::cout << t1.name << "," << things.at(2).name << std::endl;
things.at(1).rate -= 17;
std::cout << t1.rate << std::endl;
}
Based on what François Andrieux and Eljay have said (and what I would have said, had I got there first), here is the way I would do it, if you want to mutate objects you have already added to a list. All that reference_wrapper stuff is just a fancy way of passing pointers around. It will end in tears.
OK. here's the code (now edited as per OP's request):
#include <iostream>
#include <list>
#include <memory>
class Thing {
private:
int id;
int value = 0;
static int nextId;
public:
Thing() { this->id = Thing::nextId++; };
int getId() const { return this->id; };
int getValue() const { return this->value; };
void add(int n) { this->value += n; };
};
int Thing::nextId = 1;
class Storage {
private:
std::list<std::shared_ptr<Thing>> list;
public:
void add(const std::shared_ptr<Thing>& thing) {
this->list.push_back(thing);
}
std::shared_ptr<Thing> findById(int id) const {
for (std::list<std::shared_ptr<Thing>>::const_iterator it = this->list.begin(); it != this->list.end(); ++it) {
if (it->get()->getId() == id) return *it;
}
std::cout << "Not found!!\n";
exit(1);
}
};
void add_another(Storage& storage) {
storage.findById(2)->add(1);
std::shared_ptr<Thing> t4 = std::make_shared<Thing> (); t4->add(50);
storage.add(t4);
std::cout << storage.findById(4)->getValue() << "\n";
}
int main() {
std::shared_ptr<Thing> t1 = std::make_shared<Thing> (); t1->add(10);
std::shared_ptr<Thing> t2 = std::make_shared<Thing> (); t2->add(100);
std::shared_ptr<Thing> t3 = std::make_shared<Thing> (); t3->add(1000);
Storage storage;
storage.add(t3);
storage.add(t1);
storage.add(t2);
add_another(storage);
t2->add(10000);
std::cout << storage.findById(2)->getValue() << "\n";
std::cout << storage.findById(4)->getValue() << "\n";
return 0;
}
Output is now:
50
10101
50
as desired. Run it on Wandbox.
Note that what you are doing here, in effect, is reference counting your Things. The Things themselves are never copied and will go away when the last shared_ptr goes out of scope. Only the shared_ptrs are copied, and they are designed to be copied because that's their job. Doing things this way is almost as efficient as passing references (or wrapped references) around and far safer. When starting out, it's easy to forget that a reference is just a pointer in disguise.
Given that your Storage class does not own the Thing objects, and every Thing object is uniquely counted, why not just store Thing* in the list?
class Storage {
private:
std::list<Thing*> list;
public:
void add(Thing& thing) {
this->list.push_back(&thing);
}
Thing* findById(int id) const {
for (auto thing : this->list) {
if (thing->getId() == id) return thing;
}
std::cout << "Not found!!\n";
return nullptr;
}
};
EDIT: Note that Storage::findById now returns Thing* which allows it to fail gracefully by returning nullptr (rather than exit(1)).
I have two sample classes Sample and Hello
The Hello has a map which contains a map in heap, that map has Class Sample's object in it's value type.
class Hello
{
public:
map<int,Sample>* samMap;
};
And my function has a code like this
Hello * h = new Hello;
{
h->samMap = new map<int,Sample>;
for(int i=0 ; i<100000;i++)
{
Sample se;
se.a = i*2;
se.b = i*5;
se.vecInt = new vector<int>;
se.vecInt->push_back(i+2);
h->samMap->insert(make_pair(i,se));
}
}
map<int,Sample>::iterator ss = h->samMap->find(50);
if(ss != h->samMap->end())
{
cout << " Value : " << ss->second.a << " " << ss->second.b << endl;
for(int s=0; s<ss->second.vecInt->size(); s++)
{
cout << ss->second.vecInt->at(s) << endl;
}
}
From the above code, the Sample object is declared and used inside a block. Once the control comes out of block the stack object have to get cleared.
But still i can iterate the map and get the Sample's objects outside the for loop without any access violation exception.How is that possible? While inserting the object to container a new copy of object is inserted ?
Yes. Because you're not storing a pointer or reference, a copy is made when you add it to the map.
Of course, if class Sample has a destructor to delete vecInt, it will also need a copy constructor; otherwise the pointer in the map's copy becomes invalid when the local "original" goes out of scope.
The correct way here is to avoid deep copies and use memory management support from the standard library: most usages of new are a sign of poor design. For example (I'm guessing a bit about the guts of Sample)
class Sample
{
int a=0, b=0;
std::vector<int> vecint; // not a pointer, but data member
public:
Sample(int _a, int _b) // construct sample with empty vecint
: a(_a), b(_b) {}
void add(int x) // add to vecint
{ vecint.push_back(x); }
};
struct Hello
{
std::map<int,Sample> samMap;
};
Hello makeHello()
{
Hello hello;
for(int i=0; i<100000; ++i)
{
auto r = hello.samMap.emplace(std::piecewise_construct,
std::forward_as_tuple(i),
std::forward_as_tuple(i*2,i*5));
if(!r.second)
throw std::runtime_error("couldn't insert new Sample for key '"+std::to_string(i)+"'");
r.first->second.add(i+2); // add to inserted Sample
}
return hello;
}
Note: no call to new and, consequently, no call to delete. It's all done under the hood by the standard library containers std::map and std::vector.
See also the documentation for std::map and std::map::emplace.
I very recently started getting into C++, my main language has always been Java.
I want to be able to pass a reference to an object in a constructor so the object constructed can use the passed object and make changes to it.
Doing some research on the subject I've come across copy constructors but I haven't quite understood if they are strictly needed for this operation and what they really accomplish in the first place.
TLDR: I want to learn how to do the equivalent of the following Java code in C++.
Java code
class Master {
private Slave slave;
Master(Slave slave) {
this.slave = slave;
}
public void doSomethingToSlave() {
slave.doSomething();
}
public void changeSlave(Slave s) {
this.slave = s;
}
}
C++ Code ??? -my attempt so far-
class Master {
public:
Master(Slave& slave);
void doSomethingToSlave();
void changeSlave(Slave& s);
private:
Slave& slave; // Is this correct? Do I need to specify that it's a reference?
}
Master::Master(Slave& slave) { // Copy constructor needed?
this->slave = slave;
}
Master::doSomethingToSlave() {
slave.doSomething();
}
Master::changeSlave(Slave& s) {
slave = s;
}
Using Pointers ?
class Master {
public:
Master(Slave* slave);
void doSomethingToSlave();
void changeSlave(Slave* s);
private:
Slave* slave;
}
Master::Master(Slave* slave) {
this->slave = slave;
}
Master::doSomethingToSlave() {
slave.doSomething(); // How do I access the object at slave*?
}
Master::changeSlave(Slave* s) {
slave = s;
}
Here's an example which I hope elucidates the behavior:
#include <iostream>
using namespace std;
class MyType {
public:
int value;
};
int main() {
// value == 1
MyType obj1{1};
// initialize a reference to refer to obj1.
MyType &ref = obj1;
// value == 2
MyType obj2{2};
// ref refers to obj1.
cout << "A. ref.value = " << ref.value << endl;
// this actually reassigns the memory in obj1
// to the memory from obj2.
ref = obj2;
cout << "B. obj1.value = " << obj1.value << endl;
// value == 3
MyType obj3{3};
// initialize a pointer to point to obj3.
MyType *ptr = &obj3;
// ptr refers to obj3.
cout << "C. ptr->value = " << ptr->value << endl;
// now we're just reassigning the pointer value.
// this is like Java reference assignment.
// ptr now points to obj2.
ptr = &obj2;
cout << "D. obj3.value = " << obj3.value << endl;
// now we're reassigning the memory at obj2 to
// the memory from obj1.
// this is what the C++ reference assignment is doing.
*ptr = obj2;
cout << "E. obj2.value = " << obj2.value << endl;
return 0;
}
The output is as follows:
A. ref.value = 1
B. obj1.value = 2
C. ptr->value = 3
D. obj3.value = 3
E. obj2.value = 2
A Java reference is actually like a C++ pointer, but Java doesn't let you do the dereference and assignment *ptr = value.
However, I agree with what others are saying that approaching C++ with the coding style of Java isn't really a good idea. Modern C++ programs don't really use raw pointers. They use smart pointers or value objects, because C++ doesn't have garbage collection. If you're passing raw pointers around, it's difficult to figure out exactly when a particular object needs to be destroyed.
In your case, I think you'd use a std::shared_ptr<Slave>.
A value object is like Slave slave;, which is a stack-allocated object if it's declared in a method body, or it's stored directly inside the memory for an object if it's declared as a member of a class or struct.
A copy constructor (ctor) is used to copy an object, i.e. to create a copy of the object of the same type, given as argument.
In your case,
Master::Master(Slave& slave)
is not a copy ctor, and a copy ctor is not required for Master.
However, Slave should have a copy ctor and an assignment operator due to
Master::changeSlave(Slave& s) {
slave = s;
}
This is because you are assigning a copy of s to the object that slave points to. This is likely not what you wanted to do. To reassign the pointer, do use a pointer (rather smart than raw ointer) and not a reference, which cannot be reassigned.
Helpful references:
For me, C++ for Java Programmers, especially the summary of differences between C++ and Java, has helped moving from Java to C++.
About cloning: Though assignment operators and regular ctors are usually used, the clone pattern is also helpful in C++. Good examples can be found in Item 25 of More Effective C++ (Virtualizing ctors and non-member functions).
What is the best way to use Java-style references in C++? Will using shared_ptr for all classes and structs be the correct equivalent?
I highly recommend reading this answer for understanding C++ smart pointers.
Now, if by 'Java-style references' you mean you want to pass an object or struct into a method and that passed in object is not a copy of the object, but rather a reference to the object, then simply use pass by reference.
Ex:
void foo( int& ref, int val)
{
ref = ref + 1; // pass by reference
val = val + 1; // pass by value
}
...
int main()
{
int a = 10;
int b = 10;
foo(a, b);
// a is being passed by reference so foo directly modifies a
std::cout << "a = " << a << " b = " << b;
// output would be: a = 11 b = 10
}
Suppose I have a class like
class Empty{
Empty(int a){ cout << a; }
}
And then I invoke it using
int main(){
Empty(2);
return 0;
}
Will this cause any memory to be allocated on the stack for the creation of an "Empty" object? Obviously, the arguments need to be pushed onto the stack, but I don't want to incur any extra overhead. Basically I am using the constructor as a static member.
The reason I want to do this is because of templates. The actual code looks like
template <int which>
class FuncName{
template <class T>
FuncName(const T &value){
if(which == 1){
// specific behavior
}else if(which == 2){
// other specific behavior
}
}
};
which allows me to write something like
int main(){
int a = 1;
FuncName<1>(a);
}
so that I get to specialize one template parameter, while not having to specify the type of T. Also, I am hoping the compiler will optimize the other branches away inside the constructor. If anyone knows if this is true or how to check, that would be greatly appreciated. I assumed also that throwing templates into the situation does not change the "empty class" problem from above, is that right?
Quoting Stroustrup:
Why is the size of an empty class not zero?
To ensure that the addresses of two different objects will be different. For the same reason, "new" always returns pointers to distinct objects. Consider:
class Empty { };
void f()
{
Empty a, b;
if (&a == &b) cout << "impossible: report error to compiler supplier";
Empty* p1 = new Empty;
Empty* p2 = new Empty;
if (p1 == p2) cout << "impossible: report error to compiler supplier";
}
There is an interesting rule that says that an empty base class need not be represented by a separate byte:
struct X : Empty {
int a;
// ...
};
void f(X* p)
{
void* p1 = p;
void* p2 = &p->a;
if (p1 == p2) cout << "nice: good optimizer";
}
This optimization is safe and can be most useful. It allows a programmer to use empty classes to represent very simple concepts without overhead. Some current compilers provide this "empty base class optimization".
It might, it might, not, depending on circumstances. If you say:
Empty e;
Empty * ep = & e;
then obviously things have to be allocated.
Try it and see. Many compilers will eliminate such temporary objects when asked to optimise their output.
If the disassembly is too complex, then create two functions with different numbers of such objects and see if there is any difference in the stack locations of objects surrounding them, something like:
void empty1 ( int x )
{
using namespace std;
int a;
Empty e1 ( x );
int b;
cout << endl;
cout << "empty1" << endl;
cout << hex << int ( &x ) << " " << dec << ( &x - &a ) << endl;
cout << hex << int ( &a ) << " " << dec << ( &a - &b ) << endl;
}
and then try running that compared with an empty8 function with eight Empties created. With g++ on x86, if you do take the address of any of the empties you get a location between x and a on the stack, hence including x in the output. You can't assume that the storage for objects will end up in the same order as they are declared in the source code.