This question already has answers here:
Why can I use auto on a private type?
(5 answers)
Closed 9 years ago.
Let's consider the next code:
#include <iostream>
#include "mydemangled.hpp"
using namespace std;
struct A
{
private:
struct B {
int get() const { return 5; }
};
public:
B get() const { return B(); }
};
int main()
{
A a;
A::B b = a.get();
cout << demangled(b) << endl;
cout << b.get() << endl;
}
And the compiler (gcc 4.7.2) yells saying that A::B is private. All right.
So, I change the code:
int main()
{
A a;
cout << demangled(a.get()) << endl;
cout << a.get().get() << endl;
}
and it doesn't yell:
$ ./a.out
A::B
5
Meaning, I can't to create instances of A::B, but I can use it.
So, new change (the key of my question).
int main()
{
A a;
auto b = a.get();
cout << demangled(b) << endl;
cout << b.get() << endl;
}
And output:
$ ./a.out
A::B
5
What is the trouble here, being A::B private (and thus its constructors, copy constructors and so on)?
In general, access controls names or symbols, not the
underlying entities. There are, and always have been, numerous
ways of accessing private members; what you cannot do is use the
name of such a member.
In your examples, you don't use the name, so there is no
problem.
Related
This question already has answers here:
What is The Rule of Three?
(8 answers)
How to actually implement the rule of five?
(6 answers)
Closed 1 year ago.
I am new to code in C++. So, below code looks pretty decent to me.
#include<iostream>
using namespace std;
class B {};
class A {
public:
B* b;
A() {
cout << "ctor" << endl;
b = new B();
}
~A() {
cout << "dtor" << endl;
delete b;
}
};
void func(A a) {
cout << a.b << endl;
}
int main() {
A a;
cout << a.b << endl;
func(a);
cout << a.b << endl;
}
But I found an issue with this code. When I run this, it gives free(): double free detected in tcache 2 error. I know the cause of this error (it is because dtor is being called 2 times).
One way to solve the problem is, writing a copy constructor for class A where, I create a new B() like this.
A(A const& a) {
cout << "copy ctor" << endl;
b = new B();
*b = *a.b;
}
But if B is a very big class, and hence if I prefer to share b pointer, then how would I avoid this problem?
This question already has answers here:
What's the point of g++ -Wreorder?
(5 answers)
Closed 2 years ago.
I am reading into Scott Meyers book Effective c++. For constructors he recommends initialization of object data in a specific order.
Base class before derived class
Within a class data members initialized in the order which the are declared.
Appearantly not following these rules can lead to obscure behavioral bugs ... However he does'nt give any examples or go into details.
Can you give an example of what kind of bugs can occur?
For example,
struct S
{
int a;
int b;
S() : b(42), a(b + 1) {}
};
leads to undefined behavior:
As contrary as we might expect from constructor,
a is initialized before b (according to member order).
It can confusing to have the wrong order:
struct foo {
int a;
int b;
foo(int x) : b(++x),a(++x) {
std::cout << "a = " << a <<'\n';
std::cout << "b = " << b <<'\n';
}
};
Constructing a foo(1) prints:
a = 1
b = 2
Not a = 2, b = 1 as one might expect from the order of the initializer list. Real problems can occur if initialization of one member depends on another member. This is correct (but not nice):
struct bar {
int a;
int b;
bar() : b(a),a(1){
std::cout << "a = " << a <<'\n';
std::cout << "b = " << b <<'\n';
}
};
Prints:
a = 1
b = 1
And this invokes undefined behavior:
struct broken {
int a;
int b;
broken() : b(1),a(b){
std::cout << "a = " << a <<'\n';
std::cout << "b = " << b <<'\n';
}
};
Can you give an example of what kind of bugs can occur?
class foo
{
int *ptr;
int size;
public:
foo() : size(10), ptr(new int[size]) {}
};
int main()
{
foo f;
}
See the warnings here.
The size is initialized after the ptr is initialized, thus size is actually some random value when new is issued to allocate dynamically.
This question already has answers here:
Initialization Order of Class Data Members
(2 answers)
Closed 3 years ago.
I'm trying to understand member class initialization order but there is one thing that confusing me.
#include <iostream>
class Foo {
int y{7};
public:
Foo()
{
std::cout << "Foo Constructor";
}
explicit Foo(int yy) : y(yy)
{
std::cout << "Foo " << y << std::endl;
}
int gety()
{
std::cout << "Foo::gety() returning ";
return y;
}
};
class Bar {
int x;
public:
Bar()
{
std::cout << "Bar constructor" << std::endl;
}
explicit Bar(int xx) : x(xx)
{
std::cout << "Bar "<< x << std::endl;
}
int getx()
{
std::cout << "Bar::getx() returning ";
return x;
}
};
class Class {
Bar bar;
Foo foo;
public:
Class() : bar(foo.gety()), foo(5)
{
std::cout << "Class()\n";
}
void printxy()
{
std::cout << "Bar.x = " << bar.getx() << " \n" << "Foo.y = " << foo.gety() << std::endl;
}
};
int main(void)
{
Class k;
k.printxy();
return 0;
}
I'm compiling this code with gcc --std=c++11 -Wuninitialized -Wall -pedantic
In Class object there is two members of class Foo and Bar. In initialization list I'm constructing firs bar object by using constructor that takes int as argument. But as i understand foo is not constructed yet because it's second in order on initialization list. So how i don't get any errors when using foo.gety() before it's constructed?
I think C++ is guarantee that any used object is constructed. So when Foo object is constructed? Or this is undefined behavior?
This is link for coliru example: Link
Member variables are initialized in the order they are defined in the class. In your case bar will be initialized before foo (even if you change the order in the constructor initializer list).
What you're doing, using the uninitialized foo object, will lead to undefined behavior. There's no guarantee that a compiler will be able to catch it or even report it.
This question already has answers here:
Is it defined behavior to reference an early member from a later member expression during aggregate initialization?
(4 answers)
Closed 4 years ago.
Is it legal to do the following?
#include <iostream>
struct Foo
{
int bar;
int baz;
};
int main()
{
Foo instance = { 5, instance.bar };
std::cout << instance.baz << std::endl;
}
I think it's not because as far as I know the order of initialization is unspecified and the bar field can be initialized after baz.
Am I right?
https://coliru.stacked-crooked.com/a/ea97713515dd0687
If you liked your conundrum, this is really gonna bake your noodle:
#include <iostream>
struct Foo
{
int bar=0;
int baz=1;
};
const int cool(const Foo& f)
{
std::cout << "Bar: " << f.bar << " Baz: " << f.baz << std::endl;
return f.bar;
}
int main()
{
Foo instance = { 5, cool(instance) };
std::cout << instance.baz << std::endl;
}
What a previous poster correctly quoted: c++ std draft doc
...all value computations and side effects associated with a given element are sequenced before those of any element that follows it in order.
For example, in this piece of code, if line [a] is commented out, the output is 0.
inh2.cpp
#include<iostream>
using namespace std;
class A {
public:
int x;
A() { x = 10; }
};
class B : public A {
public:
int x; // <--------- [a]
B() { x = 0; }
};
int main() {
A* ab = new B;
cout << ab->x << endl;
}
results from gcc
$ g++ inh2.cpp
$ ./a.out
10
$
I have two questions:
How does ab->x resolve to 10 in the above case? The object is of type class B, and thus should value to 0.
Why does commenting Line [a] change the behaviour of the code? My reasoning is that x would have anyways been inherited, which should result in same behaviour.
My reasoning for Q #1 above:
ab points to the memory location of an object of class B. It is a physical object in the sense that all the variables with their values are assigned memory.
Variable x within this object stores value 0.
When ab->x is done, ab tells us the memory location of the object, and we go look inside it to find that x is 0. So we should print 0.
Where am I wrong here?
Yes, it is of type B, but you are assigning it as a pointer to an A, and therefore it is using the x defined on A (as when we're dealing with a pointer to A, we don't know that B even exists, even though that's what you allocated).
When you comment out the line, during the construction phase, As constructor is called first, then Bs constructor, which sets x (in its base class) to 0. There is only one x at this point, and Bs constructor is called last.
Making a some small modifications:
#include <iostream>
using namespace std;
class A {
public:
int x;
A()
:x(10)
{
std::cout << __FUNCTION__ << std::endl;
std::cout << x << std::endl;
}
virtual ~A() {}
};
class B : public A {
public:
int x; // <--------- [a]
B()
:A()
,x(0)
{
std::cout << __FUNCTION__ << std::endl;
std::cout << x << std::endl;
}
};
int main() {
A* ab = new B;
cout << "ab->x: " << ab->x << endl;
cout << "ab->A::x " << ab->A::x << endl;
B* b = dynamic_cast<B*>(ab);
cout << "b->x: " << b->x << endl;
cout << "b->A::x " << b->A::x << endl;
cout << "b->B::x " << b->B::x << endl;
}
This gives you:
A
10
B
0
ab->x: 10
ab->A::x 10
b->x: 0
b->A::x 10
b->B::x 0
This demonstrates that:
ab->x refers to A::x because ab is of type A* and there is no such thing as a virtual variable. If you want polymorphism, you'll have to write a virtual int get_x() const method.
B::x hides A::x. This is a bad idea and should be avoided. Consider using a more meaningful name for your member variables and establish whether you can reuse the base class's variable before introducing a new one.
Casting to a B* allows you access to B's members as well as A's. This should be self-explanatory.