How implement copy constructor for shared data [duplicate] - c++

This question already has an answer here:
Copy an object and make both share a member variable (C++)
(1 answer)
Closed 4 years ago.
I need to implement the copy constructor of a class.
My requirements is that all the objects need to share the same data.
Example: if I change the name of one object, all the others object get the new object name.
This is my code:
#include <iostream>
using namespace std;
class Contact
{
public:
string name;
//Constructor:
Contact(string n){
name = n;
};
/*
// Copy constructor:
*/
};
int main(int argc, const char * argv[]) {
Contact c1("albert");
Contact c2 = c1; //create a copy of c1
c1.name = "mark"; //modify c1 name
cout << c2.name << endl; //My problem: I want this output is "mark"
return 0;
}
It is possible do it with pointers?
I try this code but I get the error:
"error: lvalue required as left operand of assignment"
// Copy constructor:
Contact (const Contact &c){
&( this -> name ) = &c.name;
}

if I change the name of one object, all the others object get the new object name.
That is a strange requirement. It does not make sense that all the instances of a class have the same name.
Disregarding the propriety of the requirement, the requirement indicates that you need some piece of data that is independent of instances of the class. It can be either a static member variable of the class or a global variable, preferably scoped to a namespace.
class Contact
{
public:
static std::string name;
//Constructor:
Contact(){}
// Copy constructor:
};
or
namespace MyApp
{
// Make sure to define it in an appropriate .cpp file.
extern std::string contact_name;
class Contact
{
public:
//Constructor:
Contact(){}
// Copy constructor:
};
}

Related

Use of deleted function when using fstream

I'm receiving the message "Use of deleted function" when I combine the use of an ofstream (which I later want to use to record information) and the placement of one class inside another. Here is my minimal example:
#include <iostream>
#include <unistd.h>
#include <fstream>
class Tracker {
private:
std::ofstream tracker_file;
public:
Tracker(const std::string filename) {
tracker_file.open("tracker_file.csv", std::ios_base::app);
}
};
class Penguin {
private:
Tracker p_tracker;
public:
Penguin(
Tracker p_tracker
) : p_tracker(p_tracker) {}
};
int main()
{
Tracker penguin_tracker = Tracker("output");
Penguin gentoo(penguin_tracker);
return 1;
}
I don't understand how these are related, but if I remove the intermediate class then it works, and if I remove the ofstream it works.
In this line in the ctor of Penguin:
) : p_tracker(p_tracker) {}
You attempt to initalize the Tracker p_tracker data member.
Since you pass it an existing Tracker instance, it attempts to use the copy constuctor.
But class Tracker does not have a copy constructor. This is the "deleted function" mentioned in the error you got.
As #NathanPierson wrote in the comment below, this is because of the deleted copy constructor of the std::ofstream member variable tracker_file (and not because of the converting constructor you defined, as I originally wrote).
You could have theoretically solved it by adding a copy ctor to Tracker, something like:
Tracker(Tracker const & other)
{
// ...
}
However - as mentioned above class Tracker has a std::ofstream member which is non copyable.
So the question is what did you mean should happen in this case ?
On a side note: using the same name: p_tracker for both the class data member and the parameter passed to the constructor is a bit confusing and not recomended.
UPDATE:
To answer the question of the OP in the comment below:
If class Penguin only needs to keep a refernce to a Tracker instance, you can do the following (added "m_" prefix to members to diffrentiate them from other variables):
#include <iostream>
#include <fstream>
// No change in Tracker:
class Tracker {
private:
std::ofstream m_tracker_file;
public:
Tracker(const std::string filename) {
m_tracker_file.open("tracker_file.csv", std::ios_base::app);
}
};
// Penguin now holds a reference to Tracker:
class Penguin {
private:
Tracker & m_tracker;
public:
Penguin(
Tracker & tracker
) : m_tracker(tracker) {}
};
int main()
{
Tracker penguin_tracker("output");
Penguin gentoo(penguin_tracker);
return 0;
}
However - this solution requires you to ensure the Tracker penguin_tracker is alive as long as Tracker penguin_tracker is alive (otherwise you will have a dangling reference). In your example it is OK, just mentioned in for the general case.
Another side note: main should return 0 if all went well (not 1). See: What should main() return in C and C++?.

Declare a global variable without initialising in c++

Say I have a header file:
class.h
#pragma once
#include <iostream>
#include <string>
using namespace std;
class my_class
{
private:
string var1;
public:
my_class(string var1_val) { var1 = var1_val; };
};
I wish to declare a my_class variable as a global so it can be used across functions. However, it cannot be initialised outside the main function, as it requires user input to initialise. This poses a problem, as if the below code is run, I get: 'my_class': no appropriate default constructor available
source.cpp
#include <iostream>
#include <string>
#include "classes.h"
using namespace std;
my_class f;
int main(){
string inpt;
cout << "Enter var1 value: ";
cin >> inpt;
f = my_class(inpt);
}
How would I define the variable f so I could initialise it in main, but also use it in another function in the source.cpp file?
There are a few things mixed in the question. I'll try to address them individually.
The error message about the default constructor is exactly that: you are asking to instantiate an instance of that class but you only provide one way of doing so: the constructor with a string parameter.
Two ways you can deal with that "directly":
provide a default constructor, by either having it explicitly or making the string parameter optional, like my_class(string var1_val = {})
provide the said parameter at a time of instantiation: my_class f{""};
Have a variable "outside" in the global scope but initialized in main()... Also, a few ways to deal with that (personally I would advise against such a practice for various reasons, but providing options here for completeness):
Use pointers. Declare your variable as my_class * f{nullptr}; or, even better, as a smart pointer: std::unique_ptr<my_class> f; and instantiate the object in your main as either a naked pointer f = new my_class("string"); or a smart pointer f = std::make_unique<my_class>("args");
have that variable local to main() and pass it into whatever function you need it in
You might also look into using a Singleton Pattern where you have a factory function that manages your f (again, a horrible idea in this case, but providing it for completeness):
my_class & get_my_class(string s = {}){
static my_class * mc{nullptr};
if(!mc){ mc = new my_class{s}; } // <-- memory leak here unless you use unique_ptr
return *mc;
}
int main(){
// ...
auto & m{get_my_class("user input")};
// ...
}
void other_function(){
auto & f{get_my_class()};
// use f
}
The problem that you describe
as if the below code is run, I get: 'my_class': no appropriate default constructor available
is because you have declare another constructor with some parameter. In this case, compiler will not generate default constructor. You have to do it by yourself. so the class should look like:
class my_class
{
private:
string var1;
public:
my_class(){};
explicit my_class(string var1_val) :
var1(var1_val)
{};
};
Good practice is when you are making constructor with one argument mark it as explicit. Another good practice is to assign variables in constructor initialization list.
Best Regards
Just do this
my_class(string var1_val="") { var1 = var1_val; };
Provide default argument & you are good to go.
Just to get the compiler to shut up.
Although using global object is not a good solution.
That is not directly possible... a global class instance requires initialization (only types like int or double can be left initialized, but only in local scopes - as global they're always initialized - and this possibility of leaving variables uninitialized is also something many think is a design error of the C++ language - most younger languages do not provide this option as experience taught us that it's a source of nasty bugs and provides no real advantage).
What you want to do could be interpreted as a variation on what is normally called the "singleton pattern" ... i.e. providing all the modules access to a single instance of a class.
This in C++ is normally done using a function that returns a reference to the variable... for example:
------------------------------------------------------------ parms.h
...
struct Parms {
std::string user_name;
int user_age;
static Parms& get(); // Providing access to the singleton
};
-------------------------------------------------------- module1.cpp
#include "parms.h"
...
void foo() {
// access the singleton
std::cout << "Hello " << Parms::get().user_name << "\n";
}
---------------------------------------------------------- parms.cpp
#include "parms.h"
...
static Parms* parmsp;
void init_parms(const std::string& user_name, int user_age) {
// creates the singleton
parmsp = new Parms{user_name, user_age};
}
Parms& Parms::get() {
// Provide access to the singleton
if (!parmsp) {
throw std::runtime_error("Parameters not yet initialized");
}
return *parmsp;
}

Copy constructor with reference counting

I am trying to implement reference counting. Every copy of object should increment the counter for it.
My code looks
class Person{
public:
struct Kids{
Kids(){
count = 2;
boy = "Alex";
girl= " Lisa";
}
int count;
string boy;
string girl;
};
Person( string name , int age){
this -> name = name;
this -> age = age;
}
Person( const Person& a){
one = a.one;
one -> count++;
age = a.age;
name = a.name;
for( int i = 0; i < 5; i++){
family[i] = a.family[i];
}
};
void PrintIt(){
cout << one -> count << endl;
}
private:
Kids *one;
string name;
int age;
Kids family[5];
};
int main(){
Person one("Jogn",50);
//return 0;
Person two(one);
two.PrintIt();
}
And it throws seg fault. I have tried to pass object to copy constructor as a pointer , which resulted in the same output. How can create a copy constructor ,that will point to object via pointers , which will result in possible reference counting?
Have you tried std::shared_ptr, it is available in C++ 11. This template class has the advantages of being well tested and already developed. Here you have a link to the documentation.
Kids *one;
Seems to be uninitialized. When you copy a value to it. this value is also unitialized, since it is private, and i don't see any init code for it. You have to add something like
kids(new Kids())
in Person constructor which is not copy one.
ps. don't forget operator= and destructor.
just make a static variable in private and outside your class initialize it to zero using the scope resolution operator. Then inside your constructor increment it by one. Each time you will make an object its constructor will be called and the static variable will be incremented by one. Then when ever you want you can display that variable where ever you want (again by using scope resolution operator).

extern must have access to class constructor?

There are many ways to access class members as you all know, my problem now is. if the class constructor/deconstructor if public, the 'new' usage is allowed and also 'extern', if it is private, i can make 'GetInstance' only class which wouldn't allow 'new' usage, which is good for class that should have 1 pointing instance to them only (such as a server which counts current logged in users), and 'new' is good for classe that point to many objects (such as a class that points to a new objects, for example a new player logged int, it would create a new pointer to each on of them ), and a map would store a pointer to a 'new' of that object. The problem is, shouldnt 'extern' be allowed to access from a global object private constructors? since 'new' usage isnt allowed? Take a look at the example below:
#include <windows.h>
#include <cstdlib>
#include <iostream>
#include <map>
using namespace std;
//CMover.h-------------------------------------
#define MAX_MOVER_NAME 32
class CMover
{
private:
BOOL m_bInitialized;
BOOL m_bIsWalking;
unsigned m_uMetersPercused;
TCHAR m_szName[MAX_MOVER_NAME+1];
//CMover( LPCTSTR szMoverName, BOOL bInitialized = TRUE, BOOL bWalking = TRUE, unsigned uMeters = 0 );
public:
CMover() { };
virtual ~CMover(){};
};
//---------------------------------------------
//CMover.cpp---------------
CMover g_Mover; //CMover was created in order to have many 'new' usage, so each 'new' object points to a new player
// Making a global object of it is a big failure
//---------------------------
//CServer.h---------------
class CConnectedUsers
{
private:
CConnectedUsers() {}; //ok, new cannot access, this class should be used as 1 object only
virtual ~CConnectedUsers() {}; //to count up connected users, 'new' should never be used
public:
map<u_long,CMover*>m_UserMng;
//I Could use GetInstance, that any pointers craeted (CConnectedUsers *pCUser = CConnectedUsers::GetInstance() ) would
//point to it
static CConnectedUsers* GetInstance( void )
{
static CConnectedUsers mObj;
return &mObj;
}
};
//------------------------
//CServer.cpp ------
//Or in this case i would like to make a global object, so on CWhatever.cpp that included CServer.h i could use
//(extern CConnectedUsers g_Users;) which is also 1 object-only so no GetInstance would be needed and I would use
//(g_Users.m_UserMng...) directly after external declared
//PROBLEM is, making constructor private regulates the class to be 1 object only, but it doesn't allow external usage
//why is that???
CConnectedUsers g_Users;
//-----------------
//Main.cpp ...etcc
int main( int argc, char *argv[] )
{
CMover *pMover = new CMover;
cout << pMover << endl << &pMover << endl; //points to a new object, pointer stored in a region
CMover *pMov2 = new CMover;
cout << pMov2 << endl << &pMov2 << endl << endl; //points to a new object, pointer stored in another region
CConnectedUsers *pCUser = CConnectedUsers::GetInstance();
CConnectedUsers *pCUser2 = CConnectedUsers::GetInstance();
cout << pCUser << endl << &pCUser << endl; //points to CConnectedUsers, pointer stored in a region
cout << pCUser2 << endl << &pCUser2 << endl; //points to same CConnectedUsers, pointer stored in another region
//also another question is, do I need to check these pointers integrity by doing:
if( pCUser )
{
//??
}
system("pause>nul");
return EXIT_SUCCESS;
}
The problem isn't extern. A declaration with extern doesn't create an object, and doesn't need access to a constructor.
However, an extern reference has to find an object defined somewhere, and the one definition (not merely declaration) doesn't have access to the constructor, since it's a namespace member, not a class member.
This is completely expected and consistent. Expressions evaluated at namespace scope are outside the class and therefore have no special privilege wrt private members.
You can instead use a "lock-and-key" system to make a public constructor unusable from any other file. For example:
// header file
class Once
{
public:
struct Forward;
Once(Forward);
};
extern Once g_singleton;
// implementation file
#include "Once"
namespace { struct Local {}; }
struct Once::Forward : Local {};
Once g_singleton(Once::Forward());
It is impossible to instantiate the class from any other compilation unit, since no other compilation unit has the definition of Once::Forward, which must be passed by value to the constructor. And any attempt to define Once::Forward in any other compilation unit will be an ODR violation.

What is wrong with this c++ code?

As you can see I am new to C++, but I can't understand why y = new Person() in function foo is wrong. Thanks for your help.
I get the this error:
error: no match for ‘operator=’ in ‘y = (((Person*)operator new(32u)),
(, ))’
UPDATE:
I will accept the answer with the most upvotes by tonight or the one that is more convincing.
The argument between me and my friend is wether the function foo can change the object and propagate the change outside the function like when doing y = Person(), then also brother will change or will it remain intact?
.
CODE:
#include <iostream>
using namespace std;
class Person {
public:
int age;
char name[25];
Person() {
age = 0;
}
};
void foo(Person &y)
{
y = new Person();
}
int main()
{
Person *brother = new Person();
brother->age = 20;
cout << "age = " << brother->age << endl;
foo(*brother);
cout << "age = " << brother->age << endl;
return 0;
}
You probably come from a language were objects can only be created with new. In C++, this is not the case. And unless you really need it, you should not use new. Just create it as a normal variable:
#include <iostream>
#include <string>
class Person
{
public:
unsigned age;
std::string name;
Person(unsigned age, std::string name)
: age(age)
, name(std::move(name)) // move is C++11
{}
};
int main()
{
Person brother(8, "Tim John");
std::cout << "age = " << brother.age << '\n';
// Edit regarding the question in the comments:
brother = Person(16, "John Tim");
std::cout << "age = " << brother.age << '\n';
}
Your problem with the code above is that new returns a Pointer, and you are trying to assign a pointer to a Person, which obviously can't work.
void foo(Person &y)
{
y = new Person();
}
y is a reference, not a pointer. To reassign to y, you'd use
y = Person();
but if you really want to allocate a new person, you'd use
void foo(Person* &y) // reference to pointer to Person
With a reference, you basically say that you modify the value at the calling site.
Note that your current code leak. If you have a bare pointer that you want to manage yourself, you have to delete it first:
void foo (Person*& y)
{
delete y;
y = new Person;
}
But as you see, the code is already becoming messy without knowing your target. It might be more appropriate to delete at the calling site, or to not allocate y at all before calling foo(...).
Also note that using foo (Person* y) instead would not solve the issue of newing at the calling site:
void foo (Person *y)
{
y = new Person();
}
This of course compiles, but modifies only foo's own y variable. The caller will have an unchanged pointer.
Note that you'd better use value types or smart pointers, as it is non-trivial to write exception safe code that manually manages memory.
In function foo the line should be
y = Person();
y is not a pointer.
EDIT: actually, this is the wrong answer (even though you're currently accepted it from Jon). You are not supposed to mix heap and stack, and cause memory leaks like that. The right way to do it is to change members of the object directly. Assignment operator (operator=) will change the members of the object. Because the question is not about mixing heap and stack, but about changing object here's the code that better explains the problem. Note that there's no new here to complicate the issue.
void foo(Person &y)
{
y = Person();
}
int main()
{
Person brother;
brother.age = 20;
...
foo(brother);
...
return 0;
}
After y = Person() the brother object will be changed because y is brother and assignment operator changes the members of the object.
Never confuse yourself with the & and * operators when dealing with pointer operations.
'&' is used in different context.
&, when used in a function's formal parameters is a reference parameter , this operator passes a variable by reference(by its address).However the variable y still acts like a normal variable.
So this block of code..
void foo(Person &y)
{
y = new Person();
}
would not work as new Person() is parsing a pointer to a variable.
For example,
int * intp = new int;
int variable = intp;
this is the type of thing that's happening here.A reference parameter acts like a variable but actually has direct access to the variable due to the fact that it's a call by referance operation.
The correct way to write this function will look like this
void foo(Person ** y)
{
*y = new Person();
}
That is if you're trying to initialize a class pointer via a function.
As cooky said this is a misconception people make in c++ whom program in languages that require the new keywork in order to create an object/variable.
SOURCES
http://fredosaurus.com/notes-cpp/functions/refparams.html
you are tryng to call the "new" operator on a reference. while the "new" is used only with pointers.
pass to void foo( ) function
Person*
instead of
Person&
A little explanation :
The right way to pass a parameter depends on what you have to do!!
If you want to do side effects to the object passed to the function the right way is to declare :
void foo(Person& person)
the object person can be modified..
if you don t waant to do side effects to the object you have to declare the object 'const':
void foo(const Person& person)
the const means you cannot modify the object inside your method even if you are passing a reference..
then you can pass a pointer:
void foo(Person* person)
here you can modify the object that "person" is pointing at, but you have a copy of the original pointer.
last way to pass parameters is :
void foo(Person*& person)
here you have an alias of the original pointer. alias means "the same pointer with a different name"