I Can't properly understand what is exactly happening when class instances are creating and when an instances methods are invoking.
For example there's a folowing c++ code:
class A {
int a;
void print_my_a();
public:
A();
};
void A:: print_my_a() {
cout << a << '\n';
}
A::A(): a(10) {}
int main() {
A Aobj1 = A();
A Aobj2 = A();
Aobj1.print_my_a();
Aobj2.print_my_a();
return 0;
}
so the question is:
Do each Aobj1 and Aobj2 instance refer to only one print_my_a() method ? or they both have their own print_my_a()?
All functions are code, and all code in C++ is shared. However, it does not really make any difference, because the code cannot be modified anyway.
However, the local variables created during the runtime of each method, instance or static, are per invocation, so if you call the same method twice, concurrently or not, each method would have its own local variables.
What you see is only an abstraction over the layout of data and code in the executable. Functions have one copy in the code segment and are shared between objects.
The code for the method exists only once, but "this"-pointer "passed" to the method will be different.
If you rewrite print_my_a as follows, it gets much clearer:
void A::print_my_a() {
cout << this->a << '\n';
}
Hence:
Aobj1.print_my_a() will have this pointer pointing to Aobj1
and Aobj2.print_my_a() will have this pointer pointing to Aobj2.
An object owns it's own instance of data members. So a separate instance of int a is owned by both of your objects Aobj1 & Aobj2. The methods are not owned by the object, but they use the state of the object (the data member instances for the object) which has made the call.
Related
Consider the following code:
class A{
public:
A(){};
};
int main(){
A a = A();
std::cout << &a << std::endl;
a = A();
std::cout << &a << std::endl;
return 0;
}
Both addresses are the same. The behavior that I expected was that the second call to A() would overwrite the variable a by creating a new instance of A, thereby changing the new address of a.
Why is this so? Is there a way to statically overwrite a that I am not aware of?
Thank you!
Why is this so?
Within the scope of its lifetime, a variable is exactly one complete object (except in the case of recursion in which case there are multiple overlapping instances of the variable). a here is the same object from its declaration until the return of the function.
I expected was that the second call to A() would overwrite the variable a by creating a new instance of A,
It did that.
thereby changing the new address of a.
It didn't do that. The temporary object created by A() had a new address, but that temporary object was destroyed at the end of that full expression. a remained where it had been, and you invoked its assignment operator with the temporary object as the argument.
The variable a is allocated on the stack. Its address is not going to change for the duration of the function. The first and the second instance of class A will be created in the space taken up but the variable.
Is the following wrapper class an "OK" way of keeping an intermediate object with std::unique_ptr to access the me member without copying me?
Here is the example
#include <iostream>
#include <memory>
/* myobj from another library */
class myobj {
public:
std::string me; /* actual member of interest is larger and more
complicated. Don't want to copy of me or myobj */
/* more members in actual class */
myobj(std::string i_am) {
/* more stuff happens in constructor */
me = i_am;
}
~myobj(){
std::cout << me << ": Goodbye" << std::endl;
}
};
/* A function in another library */
void who_is_this(std::string *who){
std::cout << "This is " << *who << std::endl;
}
/* wrapper which I define */
class myobj_wrapper {
using obj_ptr = std::unique_ptr<myobj>;
obj_ptr ptr;
public:
std::string *who;
myobj_wrapper(std::string i_am):
ptr(new myobj(i_am)), who(&ptr.get()->me) {}
myobj_wrapper(myobj &the_obj): who(&the_obj.me) { }
};
int main()
{
{
myobj bob("Bob");
who_is_this(myobj_wrapper(bob).who);
}
who_is_this(myobj_wrapper("Alice").who);
return 0;
}
The resulting program yields
This is Bob
Bob: Goodbye
This is Alice
Alice: Goodbye
I define myobj_wrapper for multiple object to get the who pointer. What I am unsure of whether the object of interest (std::string in the above) will get destroyed before it is evaluated in the who_is_this function. It does not seem to from the above but should I expect this? Are there pitfalls with the above solution?
I am not sure, but here is my point of view:
who_is_this(myobj_wrapper("Alice").who);
This will create a wrapper object, that will take the string literal as its argument. Then, a myobj instance will be dynamically created, and handed over to a unique pointer. Via that instance, we get its data (the string), and make a traditional pointer from the wrapper class point to it. So, now who is pointing to me, i.e. Alice.
We pass who (which is a pointer) to:
void who_is_this(std::string *who)
which means that the function's parameter who is not a copy, but points to the original data.
So now the whole question is when the wrapper object will go out of scope (thus its data member (the unique pointer) will go out of scope too, meaning that the myobj instance which had been dynamically created will be garbage collected, which in turns means that me will go out of scope too, and so will who.
The wrapper object will go out of scope, after who_is_this() gets executed, which means that your code is OK.
I'm trying to learn the kinds of factory patterns I can use in C++. I'm not sure why I can't return a unique ptr. I can return a shared ptr just fine. Here's my code:
class FactoryMethodExample {
FactoryMethodExample() {}
public:
static FactoryMethodExample get_instance() {
return {};
}
static FactoryMethodExample * get_pointer() {
return new FactoryMethodExample;
}
static unique_ptr<FactoryMethodExample> get_unique_instance() {
return make_unique<FactoryMethodExample>();
}
static shared_ptr<FactoryMethodExample> get_shared_instance() {
return shared_ptr<FactoryMethodExample>();
}
void verify() {
cout << "I exist" << endl;
}
};
This code doesn't compile. I get this error :
error: calling a private constructor of class 'FactoryMethodExample'
return unique_ptr<_Tp>(new _Tp(_VSTD::forward<_Args>(__args)...));
Firstly, your shared_ptr and unique_ptr examples are not comparable.
make_unique creates a unique_ptr initialised with a value.
shared_ptr is just a constructor call of the shared_ptr class, which will leave it initialised with a null pointer.
This is why you are getting two different results.
The reason you have an error, is because you have a private constructor. The easiest solution is to make make_unique (and make_shared) friends.
See the following question for a bit of guidance: How to make std::make_unique a friend of my class
In addition, your function names may be misleading. get_shared_instance implies that the same instance will be returned every time, where I think you want to return a shared_ptr of a new instance?
In my place of work I see this style used extensively:-
#include <iostream>
using namespace std;
class A
{
public:
A(int& thing) : m_thing(thing) {}
void printit() { cout << m_thing << endl; }
protected:
const int& m_thing; //usually would be more complex object
};
int main(int argc, char* argv[])
{
int myint = 5;
A myA(myint);
myA.printit();
return 0;
}
Is there a name to describe this idiom? I am assuming it is to prevent the possibly large overhead of copying a big complex object?
Is this generally good practice? Are there any pitfalls to this approach?
Is there a name to describe this idiom?
In UML it is called aggregation. It differs from composition in that the member object is not owned by the referring class. In C++ you can implement aggregation in two different ways, through references or pointers.
I am assuming it is to prevent the possibly large overhead of copying a big complex object?
No, that would be a really bad reason to use this. The main reason for aggregation is that the contained object is not owned by the containing object and thus their lifetimes are not bound. In particular the referenced object lifetime must outlive the referring one. It might have been created much earlier and might live beyond the end of the lifetime of the container. Besides that, the state of the referenced object is not controlled by the class, but can change externally. If the reference is not const, then the class can change the state of an object that lives outside of it.
Is this generally good practice? Are there any pitfalls to this approach?
It is a design tool. In some cases it will be a good idea, in some it won't. The most common pitfall is that the lifetime of the object holding the reference must never exceed the lifetime of the referenced object. If the enclosing object uses the reference after the referenced object was destroyed, you will have undefined behavior. In general it is better to prefer composition to aggregation, but if you need it, it is as good a tool as any other.
It's called dependency injection via constructor injection: class A gets the dependency as an argument to its constructor and saves the reference to dependent class as a private variable.
There's an interesting introduction on wikipedia.
For const-correctness I'd write:
using T = int;
class A
{
public:
A(const T &thing) : m_thing(thing) {}
// ...
private:
const T &m_thing;
};
but a problem with this class is that it accepts references to temporary objects:
T t;
A a1{t}; // this is ok, but...
A a2{T()}; // ... this is BAD.
It's better to add (requires C++11 at least):
class A
{
public:
A(const T &thing) : m_thing(thing) {}
A(const T &&) = delete; // prevents rvalue binding
// ...
private:
const T &m_thing;
};
Anyway if you change the constructor:
class A
{
public:
A(const T *thing) : m_thing(*thing) { assert(thing); }
// ...
private:
const T &m_thing;
};
it's pretty much guaranteed that you won't have a pointer to a temporary.
Also, since the constructor takes a pointer, it's clearer to users of A that they need to pay attention to the lifetime of the object they pass.
Somewhat related topics are:
Should I prefer pointers or references in member data?
Using reference as class members for dependencies
GotW #88
Forbid rvalue binding via constructor to member const reference
Is there a name to describe this idiom?
There is no name for this usage, it is simply known as "Reference as class member".
I am assuming it is to prevent the possibly large overhead of copying a big complex object?
Yes and also scenarios where you want to associate the lifetime of one object with another object.
Is this generally good practice? Are there any pitfalls to this approach?
Depends on your usage. Using any language feature is like "choosing horses for courses". It is important to note that every (almost all) language feature exists because it is useful in some scenario.
There are a few important points to note when using references as class members:
You need to ensure that the referred object is guaranteed to exist till your class object exists.
You need to initialize the member in the constructor member initializer list. You cannot have a lazy initialization, which could be possible in case of pointer member.
The compiler will not generate the copy assignment operator=() and you will have to provide one yourself. It is cumbersome to determine what action your = operator shall take in such a case. So basically your class becomes non-assignable.
References cannot be NULL or made to refer any other object. If you need reseating, then it is not possible with a reference as in case of a pointer.
For most practical purposes (unless you are really concerned of high memory usage due to member size) just having a member instance, instead of pointer or reference member should suffice. This saves you a whole lot of worrying about other problems which reference/pointer members bring along though at expense of extra memory usage.
If you must use a pointer, make sure you use a smart pointer instead of a raw pointer. That would make your life much easier with pointers.
C++ provides a good mechanism to manage the life time of an object though class/struct constructs. This is one of the best features of C++ over other languages.
When you have member variables exposed through ref or pointer it violates the encapsulation in principle. This idiom enables the consumer of the class to change the state of an object of A without it(A) having any knowledge or control of it. It also enables the consumer to hold on to a ref/pointer to A's internal state, beyond the life time of the object of A. This is bad design. Instead the class could be refactored to hold a ref/pointer to the shared object (not own it) and these could be set using the constructor (Mandate the life time rules). The shared object's class may be designed to support multithreading/concurrency as the case may apply.
Wanted to add some point that was (somewhat) introduced in manilo's (great!) answer with some code:
As David Rodríguez - dribeas mentioed (in his great answer as well!), there are two "forms" of aggragation: By pointer and by reference. Take into account that if the former is used (by reference, as in your example), then the container class can NOT have a default constructor - cause all class' members of type reference MUST be initialized at construction time.
The below code will NOT compile if you will remove the comment from the default ctor implementation (g++ version 11.3.0 will output the below error):
error: uninitialized reference member in ‘class AggregatedClass&’ [-fpermissive]
MyClass()
#include <iostream>
using namespace std;
class AggregatedClass
{
public:
explicit AggregatedClass(int a) : m_a(a)
{
cout << "AggregatedClass::AggregatedClass - set m_a:" << m_a << endl;
}
void func1()
{
cout << "AggregatedClass::func1" << endl;
}
~AggregatedClass()
{
cout << "AggregatedClass::~AggregatedClass" << endl;
}
private:
int m_a;
};
class MyClass
{
public:
explicit MyClass(AggregatedClass& obj) : m_aggregatedClass(obj)
{
cout << "MyClass::MyClass(AggregatedClass& obj)" << endl;
}
/* this ctor can not be compiled
MyClass()
{
cout << "MyClass::MyClass()" << endl;
}
*/
void func1()
{
cout << "MyClass::func1" << endl;
m_aggregatedClass.func1();
}
~MyClass()
{
cout << "MyClass::~MyClass" << endl;
}
private:
AggregatedClass& m_aggregatedClass;
};
int main(int argc, char** argv)
{
cout << "main - start" << endl;
// first we need to create the aggregated object
AggregatedClass aggregatedObj(15);
MyClass obj(aggregatedObj);
obj.func1();
cout << "main - end" << endl;
return 0;
}
Member references are usually considered bad. They make life hard compared to member pointers. But it's not particularly unsual, nor is it some special named idiom or thing. It's just aliasing.
I do not know what methodology they use since the code base is huge.
It defined a class like this:
class ABC {
member_func(string c);
};
main() {
ABC("").member_func("this random string");
}
What is the missing code that would enable us to call ABC("");?
I did not see any object of that class created anywhere.
That simply constructs an object of type ABC, but doesn't initialize any permanent memory location with that object. I.e., the initialized object the call to the ABC constructor creates is a temporary, and is lost after the call since it is not constructed in a memory location that can be accessed after the call such as an automatic variable on the stack, a static memory location, etc. So the "missing" code to make a call like that usable in the "real-world" is to actual name an object that is constructed so that it can be accessed later... for example, something like ABC my_object(""); or ABC my_object = ABC("");.
UPDATE: In the updated code you've posted, what's taking place is again a temporary object of type ABC is being constructed, and then a non-static method of class ABC called member_func is being called on the temporary that was created by the call to ABC's constructor. Of course for this code to have any meaning in the "real world", that call to member_func would have to contain some side-effect that would be visible outside of the class instance (i.e., the class instance could be containing a data-member that is a pointer to some shared memory object that the call then modifies). Since though from the code sample you've posted there does not seem to be any side-effects from the call, it's for all intents and purposes a non-operation ... a temporary ABC class instance is created, it has a method called on the instance, and then any reference to the instance is lost since it was not constructed in a memory location accessible from the current scope of main().
class ABC
{
std::string d;
public:
ABC(std::string x) // For the ABC("").
{ d = x; }
void foo(std::string x) // For the foo("").
{ std::cout << d << std::endl << x << std::endl; }
};
int main()
{
ABC("This creates a temporary object.").foo("This calls foo().");
// Is the same as...
{
ABC obj("This creates another object.");
obj.foo("This calls obj.foo().");
} // obj is destroyed.
return(0);
}
Self explanatory... I hope. :)