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).
Related
I've a setup where I need to exchange data provided in structs between two modules .
Module 1 provides data in a shared_ptr of a struct, while module 2 needs data in a "normal" struct.
Code:
#include <iostream>
#include <memory>
#include <cstring>
struct MyStruct1 {
int x;
double y;
long long z;
};
struct MyStruct2 {
int x;
double y;
long long z;
};
int main() {
auto one = std::shared_ptr<MyStruct1>(new MyStruct1());
MyStruct2 two;
one->x = 10;
one->y = 3.141;
one->z = 1e9;
std::cout << "Size of one: " << sizeof(one) << "\n"; // Size of one: 16
std::cout << "Size of *one: " << sizeof(*one) << "\n"; // Size of *one: 24
std::cout << "Size of two: " << sizeof(two) << "\n"; // Size of two: 24
memcpy(&two, &(*one), sizeof(two));
std::cout << "two.x: " << two.x << "\n"; // two.x: 10
std::cout << "two.y: " << two.y << "\n"; // two.y: 3.141
std::cout << "two.z: " << two.z << "\n"; // two.z: 1000000000
return 0;
}
My project setup guarantees that both structs are defined exactly the same. Therefore, I make use of memcpy.
Since one is a (shared) pointer I tried to use it directly in the command
memcpy(&two, one, sizeof(two));
which results in the error no suitable conversion function from std::shared_ptr<MyStruct1>" to "const void *" exists.
As you see, I circumvent this by de-referincing and then making a normal pointer.
While this seems to work, it looks like a hard misuse.
Therefore, I'd kindly ask for your advice on how to copy data properly in this setup.
Is there a better way than memcpy?
How to address source and target properly?
What needs to be considered in terms of efficiency (speed, memory usage)?
This is a simplified example. In real application, module 1 is a ros2 message callback, which has an interface like void topic_callback(const pck::msg::msg1::SharedPtr msg) const
Additionally, the structs in my real application are nested with huge number of elements.
I do have an assertion, which double-checks that size of source and target are actually the same
By using same type for different objects assignment operator overloading can also copy content from one object to the other. I know you are trying to copy different types, maybe operator overloading for each type can be beneficial. By the way be aware of precision lost by copying elements for example first element of MyStruct1 can be float and the second type maybe integer.
Actually, my considiration here is copying obejcts of two different types can be tedious and error prone in the future even if size of two types are same.
After an update, here the solution i found. With this way you also check the types of other members.
struct MyStruct1 {
int x;
double y;
long long z;
MyStruct1& operator=(const MyStruct2& a) {
x = a.x;
y = a.y;
z = a.z;
return *this;
}
};
Note: :Since second type should be treated first it should be located above the first data type like:
struct MyStruct2 {
float x;
double y;
long long z;
};
struct MyStruct1 {
float x;
double y;
long long z;
MyStruct1& operator=(const MyStruct2& a)
{
x = a.x;
y = a.y;
z = a.z;
return *this;
}
};
And the usage of the assignment look as simple as like that in the main:
two = *one;
instead of this
memcpy(&two, &(*one), sizeof(two));
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;
}
Is it possible to convert foo from float to long (and vice versa)?
auto foo = float(1234567891234.1234);
cout << "foo: " << foo << endl;
foo = long(1234567891234.1234);
cout << "foo: " << foo << endl;
The output is always:
foo: 1.23457e+12
foo: 1.23457e+12
Not in the way you wrote it. First,
auto foo = float(1234567891234.1234);
uses auto type deduction rules to infer the type of the RHS, and the result is float. Once this is done, the type of foo is float and it is set in stone (C++ is statically typed, unlike e.g. Python). When you next write
foo = long(1234567891234.1234);
the type of foo is still float and it is not magically changed to long.
If you want to emulate a "change" of type you can at most perform a cast:
cout << "foo (as long): " << static_cast<long>(foo) << endl;
or use an additional variable
long foo_long = foo; // again you may have a loss of precision
but be aware of possible precision loss due to floating point representation.
If you have access to a C++17 compiler, you can use an std::variant<long, float>, which is a type-safe union, to switch between types. If not, you can just use a plain old union like
#include <iostream>
union Foo
{
float f;
long l;
};
int main()
{
Foo foo;
foo.f = float(1234567891234.1234); // we set up the float member
std::cout << "foo: " << foo.f << std::endl;
foo.l = long(1234567891234.1234); // we set up the long member
std::cout << "foo: " << foo.l << std::endl;
}
Live on Coliru
Or, you can use a type-erasure technique like
#include <iostream>
int main()
{
void *foo; // we will store the object via this pointer
foo = new int{42};
std::cout << *(int*)foo << '\n';
operator delete(foo); // don't do delete foo, it is undefined behaviour
foo = new float{42.42};
std::cout << *(float*)foo << '\n';
operator delete(foo); // don't do delete foo, it is undefined behaviour
}
Live on Coliru
The modern version of the code above can be re-written with a std::shared_ptr like
#include <iostream>
#include <memory>
int main()
{
std::shared_ptr<void> foo{new int{42}};
std::cout << *(int*)foo.get() << '\n';
foo.reset(new float{42.42});
std::cout << *(float*)foo.get() << '\n';
}
Live on Coliru
A std::unique_ptr<void> won't work as only std::shared_ptr implements type-erasure.
Of course, if you don't really care about storage size etc, just use 2 separate variables.
#include <iostream>
using namespace std;
struct POD
{
int i;
char c;
bool b;
double d;
};
void Func(POD *p) { ... // change the field of POD }
void ModifyPOD(POD &pod)
{
POD tmpPOD = {};
pod = tmpPOD; // first initialize the pod
Func(&pod); // then call an API function that will modify the result of pod
// the document of the API says that the pass-in POD must be initialized first.
}
int main()
{
POD pod;
ModifyPOD(pod);
std::cout << "pod.i: " << pod.i;
std::cout << ", pod.c: " << pod.c;
std::cout << " , pod.b:" << pod.b;
std::cout << " , pod.d:" << pod.d << std::endl;
}
Question> I need to design a function that modify the pass-in variable pod. Is the above function named as ModifyPOD correct? First, I initialize the struct by assigning it(i.e. pod) with the value from a local struct(i.e. tmpPOD). Then, the variable is passed to Func.
I use the local variable to initialize the pod so that I can avoid to do the following instead:
pod.i = 0;
pod.c = ' ';
pod.b = false;
pod.d = 0.0;
However, I am not sure whether this practice is legitimate or not.
Thank you
Yes, it is legitimate. I''ll just add that you can do
pod = POD();
Func(&pod);
in the ModifyPod() function which is equivalent and simpler.
#include <iostream>
class MyClass
{
public:
MyClass() :
mFirst()
{
}
int mFirst;
int mSecond;
};
int main()
{
MyClass mc;
std::cout << "mc.mFirst: " << mc.mFirst << std::endl;
std::cout << "mc.mSecond: " << mc.mSecond << std::endl;
int a;
std::cout << "a: " << a << std::endl;
return 0;
}
What is the expected output of this program?
I would think only MyClass.mFirst will be initialized to zero. However GCC initializes them all to zero, even with optimizations enabled:
$ g++ -o test -O3 main.cpp
$ ./test
mc.mFirst: 0
mc.mSecond: 0
a: 0
I'd like to know:
How is each value initialized according to the C++ standard?
Why does GCC initialize them all to zero?
Update
According to Erik the values are zero because my stack happens to contain zeroes. I tried forcing the stack to be non-zero using this construct:
int main()
{
// Fill the stack with non-zeroes
{
int a[100];
memset(a, !0, sizeof(a));
}
MyClass mc;
std::cout << "mc.mFirst: " << mc.mFirst << std::endl;
std::cout << "mc.mSecond: " << mc.mSecond << std::endl;
int a;
std::cout << "a: " << a << std::endl;
return 0;
}
However, the output stays the same:
mc.mFirst: 0
mc.mSecond: 0
a: 0
Can anyone explain why?
Update 2
Ok I figured it out. GCC was probably optimizing away unused variables.
This application shows the expected behavior:
#include <iostream>
struct MyClass
{
MyClass() : mFirst() { }
MyClass(int inFirst, int inSecond) : mFirst(inFirst), mSecond(inSecond) { }
int mFirst;
int mSecond;
};
int main()
{
// Fill the stack with non-zeroes
// Use volatile to prevent GCC optimizations.
{
volatile MyClass mc(1, 2);
volatile int a = 3;
}
{
volatile MyClass mc;
volatile int a;
std::cout << "mc.mFirst: " << mc.mFirst << std::endl;
std::cout << "mc.mSecond: " << mc.mSecond << std::endl;
std::cout << "a: " << a << std::endl;
}
return 0;
}
Output:
$ g++ -o test main.cpp
$ ./test
mc.mFirst: 0
mc.mSecond: 2
a: 3
They're (EDIT: With "They" i refer to mSecond and a which are not explicitly initialized) not initialized. Your stack happens to contain 0's so that's the values you get.
8.5/9:
If no initializer is specified for an
object, and the object is of (possibly
cv-qualified) non-POD class type (or
array thereof), the object shall be
default-initialized; if the object is
of const-qualified type, the
underlying class type shall have a
user-declared default constructor.
Otherwise, if no initializer is
specified for a nonstatic object, the
object and its subobjects, if any,
have an indeterminate initial
value; if the object or any of its
subobjects are of const-qualified
type, the program is ill-formed.
They are classified as 'undefined' meaning whatever the compiler decides or whatever was in memory at that location at the time of creation. Basically, leaving them uninitialised is leaving it up to chance and you should initialise them. The only reason for not initialising members of a struct that I can think of is if you have a very, very large array and don't want to be calling a constructor many times.