Some confusions about pointers to data-member in C++ - c++

class Foo {
public:
int a = 1;
int b = 2;
};
int main() {
Foo foo;
cout << &Foo::a << endl;//output 1
cout << &Foo::b << endl;//also output 1
}
As we know pointers to member data should point out the relative offset from the start address of the object, but as the example shows, both pointers to Foo::a and Foo::b get a 1. Would anyone can explain what happened here?

First of all, a pointer-to-member is NOT required to be implemented as an offset from the "start address of the object" (a concept which is not part of the language standard). And indeed, certain types of member pointers couldn't be implemented like that.
What you're seeing, instead, is simply basic_ostream::operator<<(bool). Pointers to members can't be implicitly converted to many other types, but they can be converted to bool. The 1 you're seeing is simply an indication that you've passed a non-null member pointer.

Although the answer provided by Sneftel is correct, this is one way to view the "actual" (internal) value of the pointer-to-members:
#include <iostream>
struct x {
int a, b;
};
int main() {
int x::* pa = &x::a;
int x::* pb = &x::b;
std::cout << pa << ' ' << pb << '\n';
std::cout << *(int*)&pa << ' ' << *(int*)&pb << '\n';
}
Try it online!
This may have different values or cause undefined behavior, depends on the implementation. Also there is no guarantee that sizeof int == sizeof pa.

Most compilers support use of the offsetof macro defined in <cstddef>. Just beware the pitfalls, quoting cppreference :
If type is not a standard layout type, the behavior is undefined
(until C++17)use of the offsetof macro is conditionally-supported
(since C++17).
If member is a static member or a member function, the behavior is
undefined.
Example:
#include <iostream>
#include <cstddef>
class Foo {
public:
int a;
int b;
};
int main() {
std::cout << offsetof(Foo, a) << std::endl;
std::cout << offsetof(Foo, b) << std::endl;
}

Related

Types should be the same but are not

I am not sure I understand why the first test evaluates to true and the second to false. I know that the information from typeid().name() is usually not reliable, but my main problem is with the typeid itself. I don't understand why the type of *test is not Location<1>, or what else is wrong. Any thoughts? Is there same wrapper around a type here that I don't see? Thanks in advance, and apologies if the answer is obvious.
#include <iostream>
#include <utility>
#include <typeinfo>
class LocationAbstract
{
virtual void get_() = 0;
};
template<int i>
class Location : public LocationAbstract
{
public:
static constexpr int test = i;
virtual void get_() override
{
return;
}
};
template <int i>
Location<i> LocationGenerator()
{
Location<i> test{};
return test;
}
int main()
{
LocationAbstract *table[10];
table[0] = new decltype(LocationGenerator<0>());
table[1] = new decltype(LocationGenerator<1>());
Location<1> *test;
try
{
std::cout << "Casting\n";
test = dynamic_cast<Location<1>*>(table[1]);
}
catch (std::bad_cast &e)
{
std::cout << "Bad cast\n";
}
// test1, evaluates to true
std::cout << (typeid(*test) == typeid(*dynamic_cast<Location<1>*>(table[1]))) << "\n";
std::cout << typeid(*test).name() << "\n";
std::cout << typeid(*dynamic_cast<Location<1>*>(table[1])).name() << "\n----\n";
// test2, why does this evaluate to false while the above evaluates to true ?
std::cout << (typeid(Location<1>()) == typeid(*dynamic_cast<Location<1>*>(table[1]))) << "\n";
std::cout << typeid((Location<1>())).name() << "\n";
std::cout << typeid(*dynamic_cast<Location<1>*>(table[1])).name() << "\n";
auto test1 = Location<1>();
auto test2 = *dynamic_cast<Location<1>*>(table[1]);
std::cout << typeid(test1).name() << " and " << typeid(test2).name() << "\n";
return 0;
}
An extra set of () makes all the difference here. In typeid(Location<1>()) and typeid((Location<1>())), Location<1>() actually means two totally different things.
In typeid(Location<1>()), Location<1>() is interpreted as a function type that returns a Location<1> and takes no parameters.
In typeid((Location<1>())), Location<1>() is interpreted as value-initializing an anonymous Location<1> object.
The typeid operator can work on either types or expressions. That is, you can say typeid(int) as well as typeid(42). Since Location<1>() can be interpreted as a type, the language does so. (Location<1>()) cannot be interpreted as a type though, so it must be interpreted as an expression. The only thing Location<1>() can mean as part of an expression is to value-initialize an anonymous Location<1> object, so typeid gives you the type of that object.
Let this be yet another reason to prefer uniform-initialization syntax when creating temporary objects; Location<1>{} would not have this ambiguity.
Examine these two lines:
std::cout << (typeid(Location<1>()) == typeid(*dynamic_cast<Location<1>*>(table[1]))) << "\n";
std::cout << typeid((Location<1>())).name() << "\n";
In the first line, you use typeid(Location<1>()). typeid can take types as well as expressions, and Location<1>() is a function type with no parameters and a return type of Location<1>.
So why does the name print the same? That's because of the second line: typeid((Location<1>())). By wrapping the argument in parentheses, it is no longer a valid type, so it is treated as an expression and the name of typeid(Location<1>) is printed. Removing the extra parentheses prints F8LocationILi1EEvE under the same mangling scheme.
To avoid the ambiguity, you can also use the type directly (typeid(Location<1>)) or use braces: typeid(Location<1>{})).

what kind of bugs can occur if object data is initialization in wrong order in c++ constructor [duplicate]

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.

Placement new on this pointer [duplicate]

This question already has an answer here:
Placement new and assignment of class with const member
(1 answer)
Closed 4 years ago.
The 2 print statements print different numbers. As far as I can see I'm not doing any dodgy const_cast here so I'm not sure what UB I could have possibly committed.
Is this code well-formed?
Can the compiler rely on the fact that A::num is const so it's allowed to print the same number ?
Code:
struct A
{
const int num = 100;
A() {}
A(int in) : num{in} {}
void call()
{
new (this) A{69};
}
};
int main()
{
A a;
std::cout << a.num << '\n';
a.call();
std::cout << a.num << '\n';
}
No, your code has UB. Remove the const on num and you don't get any UB anymore.
The problem is that the standard provides a guarantee that a const object doesn't change. But if you reuse the same storage, then you can "modify" the const object in a way.
[basic.life]p8 explicitly prohibits this by saying that the old name of the object only refers to the new object under certain conditions. One of them is that your class doesn't have any const members. So by extension, your second a.num is UB, as the a refers to the old destructed object.
However, there are two ways to avoid this UB. First, you can store the pointer to the new object:
struct A *new_ptr;
struct A {
// [...]
void call() {
new_ptr = new (this) A{69};
}
};
int main()
{
A a;
std::cout << a.num << '\n';
a.call();
std::cout << new_ptr->num << '\n'; // ok
}
Or use std::launder:
std::cout << std::launder(&a)->num << '\n'; // second access

C++ Unions in the Memory

I am fiddling with a code like following:
union Data {
int i;
double x;
std::string str;
~Data(){}
};
union Data var = {.x = 31293.932};
std::cout << var.x << "\n";
std::cout << var.str << "\n";
std::cout << var.i << "\n";
As far as I know, the union have some 64 bit thing written after I set x member to some floating point number. Then I want to see corresponding string, asuming I treated those bytes as char. But I am getting segmentation fault when I try to print it as string. Why is that? I initialized the union so I assume var.str must be initialized as well.
str is not constructed. if you must use str you must either provide a constructor for it or construct it via placement new. A full example below
#include <iostream>
#include <vector>
using namespace std;
union Data
{
int i;
double x;
std::string str;
Data() {}
Data(std::string st) : str(st) {}
~Data() {}
};
int main()
{
Data var;
var.x = 31293.932;
new (&var.str) std::string("Hello World!");
std::cout << var.x << "\n";
std::cout << var.str << "\n";
std::cout << var.i << "\n";
//destroy it
var.str.std::string::~string();
}
EDIT:
Just to expand my answer a bit...
MSDN seems to have a n00bie friendly explanation about unions than cppreference. So, check: Unions - MSDN and Unions - cppreference
You should be using char to access the bytes in the union. std::string is not a POD type and can't be used in this way.
Try this instead:
union Data {
int i;
double x;
char bytes[sizeof(double)];
~Data(){}
};
union Data var = {.x = 31293.932};
std::cout << var.x << "\n";
std::cout.write(var.bytes, sizeof(var.bytes));
std::cout << "\n" << var.i << "\n";
The full definition of what a POD type is extensive. In very simple terms it is a basic data type without a explicitly-defined copy constructor, destructor, or virtual methods and does not itself contain any such types if it is an aggregate type (like struct, class, and unions).

Using a union with unique_ptr

Trying to use a unique_ptr inside a union gives me a segfault when I try to std::move or std::make_unique it.
#include <iostream>
#include <memory>
union myUnion{
struct{std::unique_ptr<float> upFloat;}structUpFloat;
struct{std::unique_ptr<int> upInt;}structUpInt;
myUnion(){}
~myUnion(){}
};
struct myStruct{
int x;
myUnion num;
};
int main()
{
myStruct aStruct, bStruct;
aStruct.x = 1;
bStruct.x = 2;
auto upF = std::make_unique<float>(3.14);
auto upI = std::make_unique<int>(3);
aStruct.num.structUpFloat.upFloat = std::move(upF);
bStruct.num.structUpInt.upInt = std::move(upI);
std::cout << "aStruct float = " << *aStruct.num.structUpFloat.upFloat << std::endl;
std::cout << "bStruct int = " << *bStruct.num.structUpInt.upInt << std::endl;
return 0;
}
However, using a normal pointer works as expected:
#include <iostream>
#include <memory>
union myUnion{
struct{float *pFloat;}structPFloat;
struct{int *pInt;}structPInt;
myUnion(){}
~myUnion(){}
};
struct myStruct{
int x;
myUnion num;
};
int main()
{
myStruct aStruct, bStruct;
aStruct.x = 1;
bStruct.x = 2;
auto upF = std::make_unique<float>(3.14);
auto upI = std::make_unique<int>(3);
aStruct.num.structPFloat.pFloat = upF.get();
bStruct.num.structPInt.pInt = upI.get();
std::cout << "aStruct float = " << *aStruct.num.structPFloat.pFloat << std::endl;
std::cout << "bStruct int = " << *bStruct.num.structPInt.pInt << std::endl;
return 0;
}
This is using clang.3.4.2 or gcc.4.9.0. So I'm assuming that I am doing something wrong here. Any help would be appreciated.
EDIT:
Ok, so it's probably a nice thing to do to share the code I settled on. Big thanks to everyone who pointed me to managing the lifetime of my pointers in variant members using placement new.
#include <memory>
#include <iostream>
#include <vector>
struct myStruct
{
public:
union
{
std::unique_ptr<float> upFloat;
std::unique_ptr<int> upInt;
};
enum class unionType {f, i,none} type = unionType::none; // Keep it sane
myStruct(){}
myStruct(std::unique_ptr<float> p)
{
new (&upFloat) std::unique_ptr<float>{std::move(p)};
type = unionType::f;
}
myStruct(std::unique_ptr<int> p)
{
new (&upInt) std::unique_ptr<int>{std::move(p)};
type = unionType::i;
}
~myStruct()
{
switch (type)
{
case unionType::f: upFloat.~unique_ptr<float>(); break;
case unionType::i: upInt.~unique_ptr<int>(); break;
}
}
};
int main()
{
std::vector<std::unique_ptr<myStruct>> structVec;
structVec.push_back(std::make_unique<myStruct>(std::make_unique<float>(3.14f)));
structVec.push_back(std::make_unique<myStruct>(std::make_unique<int>(739)));
structVec.push_back(std::make_unique<myStruct>());
structVec.push_back(std::make_unique<myStruct>(std::make_unique<float>(8.95f)));
structVec.push_back(std::make_unique<myStruct>(std::make_unique<int>(3)));
structVec.push_back(std::make_unique<myStruct>());
for(auto &a: structVec)
{
if(a->type == myStruct::unionType::none)
{
std::cout << "Struct Has Unallocated Union" << std::endl;
}
else if(a->type == myStruct::unionType::f)
{
std::cout << "Struct float = " << *a->upFloat << std::endl;
}
else
{
std::cout << "Struct int = " << *a->upInt << std::endl;
}
std::cout << std::endl;
}
return 0;
}
Outputs:
Struct float = 3.14
Struct int = 739
Struct Has Unallocated Union
Struct float = 8.95
Struct int = 3
Struct Has Unallocated Union
Changing the active member of a union requires special care to object lifetime. The C++ Standard says (9.5p4):
Note: In general, one must use explicit destructor calls and placement new operators to change the active
member of a union.
When the members are plain old data, it generally "just works", even though you aren't calling constructors (using placement new) and destructors. That's because the lifetime for objects with trivial initialization begins "when storage is obtained" of sufficient size and correct alignment, and the union provides that.
Now you've got members with non-trivial constructor and destructor. Their lifetime doesn't begin when storage is obtained, you also have to cause initialization to finish. And that means placement new. Skipping destructor calls isn't safe either, you get undefined behavior if those destructors would have had side effects your program relies on (and a unique_ptr destructor has the side effect of deallocating its target).
Thus you are calling a move-assignment operator on a member whose lifetime hasn't begun. That is undefined behavior.
For unrestricted union, you have to manage yourself some construct/destruction.
Following may help:
union myUnion{
std::unique_ptr<float> upFloat;
std::unique_ptr<int> upInt;
myUnion(){ new (&upFloat) std::unique_ptr<float>{};}
~myUnion() {}
};
class myStruct
{
public:
~myStruct()
{
destroy();
}
void destroy()
{
switch (type)
{
case unionType::f: num.upFloat.~unique_ptr<float>(); break;
case unionType::i: num.upInt.~unique_ptr<int>(); break;
}
}
void set(std::unique_ptr<int> p)
{
destroy();
new (&num.upInt) std::unique_ptr<int>{std::move(p)};
type = unionType::i;
}
void set(std::unique_ptr<float> p)
{
destroy();
new (&num.upFloat) std::unique_ptr<float>{std::move(p)};
type = unionType::f;
}
public:
enum class unionType {f, i} type = unionType::f; // match the default constructor of enum
myUnion num;
};
int main()
{
myStruct aStruct, bStruct;
aStruct.set(std::make_unique<float>(3.14f));
bStruct.set(std::make_unique<int>(3));
std::cout << "aStruct float = " << *aStruct.num.upFloat << std::endl;
std::cout << "bStruct int = " << *bStruct.num.upInt << std::endl;
return 0;
}
In C++17, you may use std::variant instead of your own struct
From this reference:
If a union contains a non-static data member with a non-trivial special member function (copy/move constructor, copy/move assignment, or destructor) that function is deleted by default in the union and needs to be defined explicitly by the programmer.
I assume that the reason you wrapped the pointers in simple structures is because you could not build it otherwise, due to the restrictions imposed by the above paragraph.
What you have done instead is bypassed the compilers safety-guards, and probably have undefined behavior in your code.
From ยง12.6.2[class.base.init]/p8 of the standard (emphasis added):
In a non-delegating constructor, if a given non-static data member or
base class is not designated by a
mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no
ctor-initializer) and the entity is not a virtual base class of an abstract class (10.4), then
if the entity is a non-static data member that has a brace-or-equal-initializer, the entity is initialized as specified in 8.5;
otherwise, if the entity is a variant member (9.5), no initialization is performed;
[...]
Union members are variant members, which means that the unique_ptrs are left uninitialized. In particular, no constructor, not even the default one, is called. Technically, the lifetime of these unique_ptrs never even began.
The unique_ptr move assignment operator must delete what the unique_ptr is currently holding, but you are move-assigning to an uninitialized "unique_ptr" containing garbage values. As a result, your move assignment likely caused an attempt to delete a garbage pointer, causing a segfault.