When I provide a constructor for class A, I don't get the unreferenced local variable why?
What does the empty constructor do to eliminate the warning?
class A
{
public:
A() {}
};
int main()
{
A a;
}
This is only a theory, but because a constructor may contain code that can cause side effects, someone may decide to construct an unused object just to run that code. If you have no constructor and never reference an object that you've constructed, then it can safely be determined that the object has no purpose.
For example if A is something that holds a mutex lock (and release the lock when destructed), then this code
int main()
{
A a;
// other actions
}
is able to keep this function thread-safe, even a does not be referenced.
Related
Have looked at various similar questions here but still can't figure out why the following code does not compile:
// these three are defined somewhere
class A;
std::unique_ptr<A> make_a();
void take_a(std::unique_ptr<A>&&);
int main(){
take_a(make_a()); // this fails
return 0;
}
According to this:
If the default deleter is used, T must be complete at the point in
code where the deleter is invoked, which happens in the destructor,
move assignment operator, and reset member function of
std::unique_ptr.
As far as I understand, none of these (destructor, move assignment operator, nor reset member function) happens in main.
So why does compiler needs the definition of A here?
Since main has a unique_ptr within its scope, realistically it would need to know how to delete the object it holds.
It's possible that take_a doesn't actually take ownership of the object, thus main would need to delete.
main gets a temporary unique_ptr from make_a(), let's call it X. It then passes an rvalue reference to X to take_a. It still has the destroy X. Hence, it has to call the destructor after take_a, even though X would typically be empty at that point.
We need class A description (at least constructor and destructor) in order to create and move std::unique_ptr<A> objects; take_a(make_a()) is creating such object because make_a() is pass-by-value. It first creates a new unique_ptr<A> object, initialize it (using default constructor), and then update its value and returns this new object. Here the default constructor/destructor is being used, which the compiler is unable to find.
#include <bits/stdc++.h>
class A {
public: A() {}
public: ~A() {}
};
std::unique_ptr<A> make_a() {
std::cout << "make";
std::unique_ptr <A> tt = nullptr;
return tt;
}
void take_a(std::unique_ptr<A>&&) {
std::cout << "take";
}
int main(){
take_a(make_a()); // this works now
return 0;
}
Edit: Forgot to add the link. Works the other way too.
In code like this:
class X {
X(const X&) {
// ...
}
X(const X&&) {
// ...
}
// ...
};
void f() {
X a;
// ...
X b = a;
// ... code that doesn't use a
}
My understanding is that the last statement calls the copy constructor not the move constructor. Assuming a is never used again in f(), can the compiler automatically optimize this statement to use the move constructor instead?
P.S. I know about std::move(), but I'm asking about automatic move.
You'd need to write a spec that somehow correctly handles
void f() {
X a;
g(a); // stash a reference to a somewhere
X b = a; // can't move from a!
g2(); // use the reference stored by g
}
For the move to be safe, you'd need to prove that subsequent code, including all the functions it calls, does not access a directly or indirectly, which is impossible in the general case because the definitions of these functions may not be available to the compiler (e.g., in a different translation unit).
It is difficult/impossible for a compiler to know that a is unreferenced except in trivial scenarios. Any outside function could have saved a pointer or reference to a, and any outside function could be relying on said pointer's contents.
In the situation where no outside functions are involved, I guess that optimization could be possible.
The optimization would not be entirely safe without more rigorous analysis. For example, a local object might have been initialized with the address of a and do something on it upon destruction, which would happen after the last statement X b = a;.
In C++, when a function is called, a new stack frame is added to the call stack, containing its parameters and local variables (and other things). Does this also happen when an object constructor is called?
If so, does this change when the constructor uses an initialization list? What is the structure of this stack frame? Does it contain the object's member variables (which must be in the heap after the execution of the constructor)?
You don't need to think constructor especially. It's just a kind of function - for example, This C++ code is
class Test
{
private:
int m_a;
public:
Test() : m_a(0) { puts("Test::Test()"); }
explicit Test(int i) : m_a(i) { puts("Test::Test(int)"); }
void f(char c) { puts("Test::f(char)"); }
~Test() { puts("Test::~Test()");
};
int main()
{
Test t1;
Test t2(3);
t1.f('a');
}
almost similar to
struct Test
{
int m_a;
};
void Test__ctor_0(Test *thiz) { thiz->m_a = 0; puts("Test::Test()"); }
void Test__ctor_1(Test *thiz, int i) { thiz->m_a = i; puts("Test::Test(int)"); }
void Test__f(Test *thiz, char c) { puts("Test::f(char)"); }
void Test__dtor_(Test *thiz) { puts("Test::~Test()"); }
int main()
{
struct Test t1;
Test__ctor_0(&t1);
struct Test t2;
Test__ctor_1(&t2, 3);
Test__f(&t1, 'a');
Test__dtor_(&t1);
Test__dtor_(&t2);
}
this C code.
Of course, the stack frame can be created when you call ctor, if it's not inlined or compiler optimizes call not to create stack frame to reduce the decrease of performance.
(In cdecl of x86, this pointer is sent through ecx register, unlike other parameter. So if the constructor don't use any local variables and don't have any additional parameters, stack frame could be not created.)
Construction is handled like any other method call.
If it doesn't get inlined by the optimizer, a stack frame will be created holding an implicit "this" pointer and all passed-in parameters.
Most architectures' ABIs call member functions by putting the this-pointer into a specific register, or by pushing it onto the stack at a particular position. Constructors are a little unusual language-wise, but from the point of view of the ABI they follow this pattern.
In general, the this-pointer is treated as an implicit first argument to the function. For instance, under the normal x86 calling convention, a pointer to the object is at the "bottom" (memory-order-wise) of the stack. The member variables themselves aren't on the stack; that wouldn't make any sense, because the constructor (as with other member functions) might need to write to those variables, and those writes would need to affect the "real" copy of the object. Hence pushing a pointer to them instead.
Object construction involves more than just the execution of constructor body. First off, all the base subobjects and member subobjects are initialized, and only then does the contructor body run. So when a particular constructor is selected for object construction, the subobject constructors run first, and their arguments are given by the original constructor's initializer list. Afterwards, the constructor body runs, more or less like a normal function, with parameters populated from the constructor arguments.
Simple example:
struct A
{
A() : i(int()) {}
const int& i;
};
Error from gcc:
a temporary bound to 'A::i' only persists until the constructor exits
Rule from 12.2p5:
A temporary bound to a reference member in a constructor’s
ctor-initializer (12.6.2) persists until the constructor exits.
Question
Does anybody know the rationale for this rule? It would seem to me that allowing the temporary to live until reference dies would be better.
I don't think the not extending to the object lifetime needs justification. The opposite would!
The lifetime extension of a temporary extends merely to the enclosing scope, which is both natural and useful. This is because we have tight control on the lifetime of the receiving reference variable. By contrast, the class member isn't really "in scope" at all. Imagine this:
int foo();
struct Bar
{
Bar(int const &, int const &, int const &) : /* bind */ { }
int & a, & b, & c;
};
Bar * p = new Bar(foo(), foo(), foo());
It'd be nigh impossible to define a meaningful lifetime extension for the foo() temporaries.
Instead, we have the default behaviour that the lifetime of the foo() temporary extends to the end of the full-expression in which it is contained, and no further.
The int() in your constructor initialization list is on the stack.
Once that value is set, int() goes out of the scope and the reference becomes invalid.
What memory would it live in?
For it to work the way you propose, it can't be on the stack since it has to live longer than any single function call. It can't be put after struct A in memory, because it would have no way to know how A was allocated.
At best, it would have to be turned into a secret heap allocation. That would then require a corresponding secret deallocation when the destructor runs. The copy constructor and assignment operator would need secret behavior too.
I don't know if anyone ever actually considered such a way of doing it. But personally, it sounds like too much extra complexity for a rather obscure feature.
Having a simple class:
class A {
public:
A() {}
void set(int value) { value_ = value; }
private:
int value_;
};
and its global instance:
A a;
Is it OK to call method set on a not yet constructed object a? That can happen when for example a.set(123) is called from a constructor of another global object in another translation unit.
Will the value in the object a set by calling a.set(123) remain when the non-parametric and empty constructor of A is later called for object a?
Is it ok to call method set on a not yet constructed object a?
No. You may not call member functions for an object that has not yet begun construction.
(Since the answer is no, your second question requires no answer.)
If you may need to access this global instance from multiple translation units during dynamic initialization, you can use the Meyers singleton technique:
A& global_a()
{
static A a;
return a;
}
a will be initialized when global_a() is first called. Note that in a multithreaded program you may need to concern yourself with synchronization of the initialization.
When you write
A a;
a is a constructed object now. In case A is a then A default constructor was already been called
If in 1) you mean it's ok to call set in the constructor, then yes, that's fine because it isn't a virtual method. You cannot call a virtual method in the constructor.
As for 2), what you're asking isn't really clear. The constructor is only called once (although there are ways around that sort of thing, but don't do them) and that is when the object is first created. You can't call the constructor on a a second time so the question doesn't really make sense.