Reputation: 122
Say I have a struct like this. Is it legal C++ to have a member of the struct point to another member inside it? How are these stored?
struct Foo {
int m1{};
int m2{};
int* pint{};
std::string str{};
const char* pstr{};
};
I'm setting the members first, and then the pointers. Is this legal?
Foo a {
.m1 = 10,
.m2 = 15,
.str = "Hello, Earth!"
};
a.pint = &a.m1;
a.pstr = a.str.c_str();
I'm setting the pointers first, and then the members. Is this legal?
Foo a {};
a.pint = &a.m1;
a.pstr = a.str.c_str();
a.m1 = 10,
a.m2 = 15,
a.str = "Hello, Earth!"
I checked on Godbolt.org, and it seems to work even at the highest optimization levels, but wanted to make sure it was legal C++ lest the UB kraken devour my program.
Is there a way I can aggregate initialize the pointers inline to the members of the struct? Something like this?
Foo a {
.m1 = 10,
.m2 = 15,
.pint = // address to m2?
.str = "Hello, Earth!",
.pstr = // something.c_str()?
};
P.S. How do I phrase this question, looking for struct member pointing to internal member (and variations) didn't yield any useful results.
Edit: I know copy/move is broken for this. A request to the people who answer. If possible, please point me to the specification so that I can develop a habit of reading and interpreting it properly.
Upvotes: 1
Views: 90
Reputation: 206577
Based on the comment
no, the members always point to other members, if at all.
I would suggest changing the member variables pint
and pstr
from being pointers to objects to pointers to member variables.
struct Foo {
int m1{};
int m2{};
std::string str{};
int Foo::* pint{nullptr};
std::string Foo::* pstr{nullptr};
};
Then, you can use the default copy constructor and copy assignment operator without any problem. The following should work.
Foo a {10, 15, "Hello, Earth!", &Foo::m1, &Foo::str};
std::cout << a.*(a.pint) << std::endl;
std::cout << a.*(a.pstr) << std::endl;
// Default copy constructor works fine.
Foo b = a;
std::cout << b.*(b.pint) << std::endl;
std::cout << b.*(b.pstr) << std::endl;
// Default copy assignment works fine.
Foo c;
c = a;
std::cout << c.*(c.pint) << std::endl;
std::cout << c.*(c.pstr) << std::endl;
See it working at https://ideone.com/qE1WVn.
Re:
Could you also answer the last part of the question please (aggregate initialize the pointers inline to the members of the struct)?
You may also use
struct Foo {
int m1{};
int m2{};
std::string str{};
int Foo::* pint{&Foo::m1};
std::string Foo::* pstr{&Foo::str};
};
and
Foo a {
.m1 = 10,
.m2 = 15,
.str = "Hello, Earth!",
.pint = &Foo::m2,
.pstr = &Foo::str
};
Upvotes: 2
Reputation: 275385
This is legal, but the default copy/move operations are broken.
Either add
Foo(Foo const&)= delete;
Foo(Foo&&)=delete;
Foo&operator=(Foo const&)= delete;
Foo&operator=(Foo&&)=delete;
or implement them to do something sensible.
Upvotes: 3