Standard layout and non-copyable property - c++

C++11, §9/7:
A standard-layout class is a class that:
has no non-static data members of type non-standard-layout class (or array of such types) or reference,
has no virtual functions and no virtual base classes,
has the same access control for all non-static data members,
has no non-standard-layout base classes,
either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and
has no base classes of the same type as the first non-static data member.
So, is there a way to make a class with standard layout non-copyable? If yes, how?
Inheriting privately from boost::noncopyable will not work, because it made copy constructor private (hence not a standard layout). The boost::noncopyable's implementation is like this :
class noncopyable
{
protected:
noncopyable() {}
~noncopyable() {}
private: // emphasize the following members are private
noncopyable( const noncopyable& );
const noncopyable& operator=( const noncopyable& );
};
Because of the private section, it is not a standard layout class. I am also note sure if private inheritance break any standard layout rule.
#include <boost/noncopyable.hpp>
#include <iostream>
const int N = 50;
struct A
{
int data[N];
};
struct B : private boost::noncopyable
{
int data[N];
};
struct C
{
A data[10];
};
struct D : private boost::noncopyable
{
B data[10];
};
int main() {
std::cout<<sizeof(A)<<std::endl;
std::cout<<sizeof(B)<<std::endl;
std::cout<<sizeof(C)<<std::endl;
std::cout<<sizeof(D)<<std::endl;
}
The output is :
200
200
2000
2004
The example above shows that inheriting privately from boost::noncopyable changes the class into NOT standard layout compliant.
I am not sure if this is a g++ bug (I am using g++ 4.6.1), or the standard is somehow violated.

I think there is a confusion here:
the standard layout property is affected by attributes (and only attributes)
the copyable property is affected by methods (their presence, absence and accessibility)
The two concepts are orthogonal.
UPDATE:
The following display the very same behavior that boost::noncopyable:
#include <iostream>
struct foo {};
struct B : foo { int data; };
struct D : foo { B data; };
int main() {
D d;
std::cout << (char*)(&d.data) - (char*)(&d) << "\n";
}
The result is 4.
I believe this is because of:
has no base classes of the same type as the first non-static data member.
Indeed, experiment shows that introducing a int a; in D prior to data does not increases its size. I think that the fact that B inherits from foo means that data (first non-static data member) is considered to be the same type as foo (base class of D).
This leads to an ambiguity: foo* f = &d would have the same address as foo* g = &b.data; if the compiler did not introduce this padding.

There are two things you need to do to make your class non copyable:
Make the copy constructor private.
Make the assignment operator private. (Where it gets assigned another type of the same kinds as the class itself).
You don't need to inherit from some boost class just to get that behavior.
And may I add, who cares about some fancy 'standard layout' idea. Program what you need and don't succumb to this extreme space theory.

Related

Inheriting constructors in C++20 (Visual Studio 2019)

I am using Visual Studio 2019 (v16.10.3) with /std:c++latest and this compiles:
class Base
{
public:
Base(int x) {}
};
class Derived : public Base
{
// no constructors declared in Derived
};
int main() {
Derived d(5);
}
For the previous versions of the standard I have to declare inherited constructors with the using directive:
class Derived : public Base
{
using Base::Base;
};
Is this something new that was put in C++20 or is it some Microsoft specific thing?
Is this something new that was put in C++20 or is it some Microsoft specific thing?
Not with relation to inherited constructors. What changed is that aggregate initialization may use parenthesis under certain conditions. Derived is considered an aggregate on account of having no private parts, so we initialize its bases and members directly.
It even works when we add a public member:
class Base
{
public:
Base(int ) {}
};
struct Derived : public Base
{
// no constructors declared in Derived
int y;
};
int main() {
Derived d(5, 4);
}
Live
This is the result of C++17 allowing classes with base classes to still be considered aggregates combined with C++20 rules allowing aggregate initialization to work with () constructor syntax if the values in the parentheses would work (and wouldn't call a constructor). So while it looks like a constructor call, it's actually aggregate initialization.
Derived doesn't have a constructor matching Base's constructor; you're merely initializing the aggregate Derived by providing a valid initializer for its subobject Base.

Do public/private/protected change the arrangement of a struct in memory?

Edit: I just realized a much simpler way to ask this question:
Given the following two structs:
class Thing {public: int a; public: int b; public: int c;}
class Thing {public: int a, private: int b; public: int c;}
Are the members a, b, and c guaranteed to be in the same order in memory for both of these definitions?
Old Question
Let's say we have this C++ code in fileA.cpp:
class Thing
{
public:
int a;
double num;
Thing()
{
b = 10;
}
float getB()
{
return b;
}
private:
float b;
Thing * other;
}
void doSomething(Thing thing);
int main()
{
Thing thing;
doSomething(thing);
std::cout << thing.b;
}
And let's say we have this code in fileB.cpp:
class Thing
{
public:
int a;
double num;
Thing()
{
b = 10;
}
float getB()
{
return b;
}
float b;
private:
Thing * other;
}
void doSomething(Thing thing)
{
thing.b = 30;
}
Assuming the compiler wouldn't complain, would this code work as expected? That being, is the arrangement of a struct's data independent of whether or not certain components are public, private, or protected?
Edit: To make it more obvious, the only difference between the two definitions of Thing is the fact that float b; is private in fileA.cpp but public in fileB.cpp.
The standard makes no such guarantee. You have layout guarantees only for standard-layout classes:
A standard-layout class is a class that:
has no non-static data members of type non-standard-layout class (or array of such types) or reference,
has no virtual functions (10.3) and no virtual base classes (10.1),
has the same access control (Clause 11) for all non-static data members,
has no non-standard-layout base classes,
either has no non-static data members in the most derived class and at most one base class with
non-static data members, or has no base classes with non-static data members, and
has no base classes of the same type as the first non-static data member.
(C++14, [class] ¶7)
If a class is standard-layout, its layout is well defined (and two standard layout classes that have a layout-compatible initial sequence may read each other's layout-compatible members through a union).
However, here it is not the case, as you have different access specifiers throughout the class. In particular, it's explicitly stated that
The order of allocation of non-static data members with different access control is unspecified
(C++14, [class.mem] ¶13)
That being said, I never worked with any real world compiler that ever exploited this flexibility offered by the standard - every compiler I know uses the access specifiers for compile-time checks, but ignores them completely as far as members layout is concerned.

How private/protected/public affect the ABI?

What I want is for some class members to be sometimes private and others times public. These members are supposed to be accessible by some modules and inaccessible by others.
Imaging this class:
class Foo {
public:
...
private:
...
protected:
...
internal:
int x;
};
In module X the internal is defined as:
#define internal public
and in module Y it's defined as:
#define internal private
So the real question is if this trick is acceptable by the standard or if it will change the signature of the class (or its members) in any way.
I know that friend and PIMPL are for this kind of job but friend can get extremely messy and PIMPL's performance (an indirection and the fact that you can't inline) are not acceptable for the codebase I'm working on.
It is an ODR violation and hence invokes undefined behaviour. (See also basic.def.odr]/6.1 "each definition of D shall consist of the same sequence of tokens").
However, a common implementation is that public, private, protected have no impact on class layout so it will work.
You are skating on thin ice; there is nothing to stop a compiler putting all the public members first, then the protected ones, then the private ones. More to the point, in general, the order of declaration is required to be the order in memory so
struct T {char a; int b; char c};
is required to have a, then b, then c. This is to ensure C compatability. However, there is no requirement on the ordering of elements with different access (See [class.mem]/9.2 p13: "Nonstatic data members of a (non-union) class with the same access control (Clause 11) are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified (Clause 11)". So given
struct T {char a; int b; private: char c};
the compiler can reorder the members and put c in the gap between a and b.
Final note to EJP and others who think these are declarations not defintions: I have given two definitions of T above; a declaration would look like struct T;.
Edit: Thanks to Fanael for the cite from the standard.
The C++ originally seemed to consider that private members could be placed somewhere other than next to public members, perhaps so they could be a protected region in hardware, so it is conceivable that the public and private sections could be moved relative to each other.
It is possible to test your code without redefining public / private using tricks by Herb Stutter GOTW 76 and completed to a fully functional system with this data here litb safer private member access
Given a class as follows....
struct A {
A(int a):a(a) { }
private:
int a;
};
A class robber is required...
template<typename Tag, typename Tag::type M>
struct Robber {
friend typename Tag::type get(Tag) {
return M;
}
};
A utility class allowing multiple steals....
template<typename Tag, typename Member>
struct TagBase {
typedef Member type;
friend type get(Tag);
};
Declaring a theft intent becomes
struct A_f : TagBase<A_f, int A::*> { };
template struct Robber<A_f, &A::a>;
Then stealing the data....
int main() {
A a(42);
std::cout << "proof: " << a.*get(A_f()) << std::endl;
}

calling copy-constructor after simple inheritance

I have a doubt regarding some concept of inheritance, i am stating what i know, please correct me if i am wrong.
Private members of base class are inherited by the derived class but derived class can't access them by any means.
Protected members of base class are inherited by the derived class but derived class can't access it directly, but by the help of some of its member functions.
Now in the following code:
class A
{
protected:
A(const A&){}
A operator=(const A &){}
int t;
public:
A(int r) {t=r;}
A(){t=0;}
};
class B : public A
{
A a;
public:
void make(void)
{
//A b(a); //LINE 1 -------COPY CONSTRUCTOR BEING CALLED ---protected member of base class
cout<<t; //LINE 2 -------protected member of base class
}
};
int main()
{
B b;
b.make();
return 0;
}
Why there is error for LINE 1 coming??
Why we can't call copy-constructor for object of A?
Many many thanx in advance
A protected member can only be accessed by other members of the same complete object, during construction, destruction, or via the this pointer(*).
In your example class hierarchy, a B object has two subobjects of type A:
The base class subobject, which it gets by deriving from A, and
The data member subobject named a, which it gets by declaring a.
A member of B may only access protected members from the first A subobject, not from the second, because only the first directly uses the this pointer (note that your expression cout << t is semantically equivalent to cout << this->t).
Access to the members of the data member do not directly use the this pointer: if you tried to access this->a.t from B::make, the this pointer is not used directly to access the t. In your declaration A b(a);, the copy constructor is called not for this, but for the new A object you are constructing, the local variable named b.
(*) Or, of course, by any member in the class that declares it: any member function of B can call any other member function of B

Base-from-Member Idiom in C++

The following code is from here:
#include <streambuf> // for std::streambuf
#include <ostream> // for std::ostream
class fdoutbuf
: public std::streambuf
{
public:
explicit fdoutbuf( int fd );
//...
};
class fdostream
: public std::ostream
{
protected:
fdoutbuf buf;
public:
explicit fdostream( int fd )
: buf( fd ), std::ostream( &buf ) // This is not allowed.
// buf can't be initialized before std::ostream.
{}
//...
};
I didn't really understand the comment. Why "buf can't be initialized before std::ostream"? Can I use some help understanding this?
The order of initialization is determined by the order of declaring your class members, and inherited classes come before all of that. Take a simple example that illustrate the basic problem without referring to inheritance :
class C
{
int a, b;
public:
C() : b(1), a(b) {} // a is initialized before b!
};
The code doesn't do what you think! a is initialized first, then b is initialized to one. So it depends on the order of the declaration not the order in the initialization list:
int a, b;
Now, the same idea applies to base classes which are initialized before the derived class members. To solve this problem, you create a class that you inherent which contains the member you want to initialize from a base class. Of course, that helper class must come before the one you are actually deriving from.
You have to call the base class constructor before you initialize your member variables, but you pass a pointer to buf (a member variable which is undefined at this point) to this constructor.