Define all constants as const references? - c++

Is there a best practice to define a constant? Here is a small example:
#include <vector>
struct mystruct {
std::vector<double> data;
mystruct() : data(100000000,0) {};
};
int main(){
mystruct A;
int answer = 42;
const mystruct& use_struct_option_1 = A; // quick
const mystruct use_struct_option_2 = A; // expensive
const int& use_answer_option_1 = answer; // good practice?
const int use_answer_option_2 = answer; // ubiquitous
}
Obviously, initializing use_struct_option_2 that way is expensive because the copy constructor of mystruct is called whereas the way of initializing use_struct_option_1 is quicker.
However, does the same apply to types such as integers?
From the code I've been locking at I can tell that
const int use_answer_option_2 = answer;
is much more common than
const int& use_answer_option_1 = answer;
Which one is preferable?

These do different things. For example, in the int case:
answer = 43;
cout << use_answer_option_1 << '\n'; // 43
cout << use_answer_option_2 << '\n'; // 42
In other words, option 2 makes a copy and option 1 doesn't.
Decide whether you want to make a copy or not (i.e. whether you want to see changes to the original initializer reflected in your reference). The mystruct case is the same.

Related

Copy data from shared_ptr to struct

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));

How to make a data member const after but not during construction?

Without relying on const_cast, how can one make a C++ data member const after but not during construction when there is an expensive-to-compute intermediate value that is needed to calculate multiple data members?
The following minimal, complete, verifiable example further explains the question and its reason. To avoid wasting your time, I recommend that you begin by reading the example's two comments.
#include <iostream>
namespace {
constexpr int initializer {3};
constexpr int ka {10};
constexpr int kb {25};
class T {
private:
int value;
const int a_;
const int b_;
public:
T(int n);
inline int operator()() const { return value; }
inline int a() const { return a_; }
inline int b() const { return b_; }
int &operator--();
};
T::T(const int n): value {n - 1}, a_ {0}, b_ {0}
{
// The integer expensive
// + is to be computed only once and,
// + after the T object has been constructed,
// is not to be stored.
// These requirements must be met without reliance
// on the compiler's optimizer.
const int expensive {n*n*n - 1};
const_cast<int &>(a_) = ka*expensive;
const_cast<int &>(b_) = kb*expensive;
}
int &T::operator--()
{
--value;
// To alter a_ or b_ is forbidden. Therefore, the compiler
// must abort compilation if the next line is uncommented.
//--a_; --b_;
return value;
}
}
int main()
{
T t(initializer);
std::cout << "before decrement, t() == " << t() << "\n";
--t;
std::cout << "after decrement, t() == " << t() << "\n";
std::cout << "t.a() == " << t.a() << "\n";
std::cout << "t.b() == " << t.b() << "\n";
return 0;
}
Output:
before decrement, t() == 2
after decrement, t() == 1
t.a() == 260
t.b() == 650
(I am aware of this previous, beginner's question, but it treats an elementary case. Please see my comments in the code above. My trouble is that I have an expensive initialization I do not wish to perform twice, whose intermediate result I do not wish to store; whereas I still wish the compiler to protect my constant data members once construction is complete. I realize that some C++ programmers avoid constant data members on principle but this is a matter of style. I am not asking how to avoid constant data members; I am asking how to implement them in such a case as mine without resort to const_cast and without wasting memory, execution time, or runtime battery charge.)
FOLLOW-UP
After reading the several answers and experimenting on my PC, I believe that I have taken the wrong approach and, therefore, asked the wrong question. Though C++ does afford const data members, their use tends to run contrary to normal data paradigms. What is a const data member of a variable object, after all? It isn't really constant in the usual sense, is it, for one can overwrite it by using the = operator on its parent object. It is awkward. It does not suit its intended purpose.
#Homer512's comment illustrates the trouble with my approach:
Don't overstress yourself into making members const when it is inconvenient. If anything, it can lead to inefficient code generation, e.g. by making move-construction fall back to copy constructions.
The right way to prevent inadvertent modification to data members that should not change is apparently, simply to provide no interface to change them—and if it is necessary to protect the data members from the class's own member functions, why, #Some programmer dude's answer shows how to do this.
I now doubt that it is possible to handle const data members smoothly in C++. The const is protecting the wrong thing in this case.
Something along these lines perhaps:
class T {
private:
T(int n, int expensive)
: value{n-1}, a_{ka*expensive}, b_{kb*expensive} {}
public:
T(int n) : T(n, n*n*n - 1) {}
};
One possible way could be to put a and b in a second structure, which does the expensive calculation, and then have a constant member of this structure.
Perhaps something like this:
class T {
struct constants {
int a;
int b;
constants(int n) {
const int expensive = ... something involving n...;
a = ka * expensive;
b = kb * expensive;
}
};
constants const c_;
public:
T(int n)
: c_{ n }
{
}
};
With that said, why make a_ and b_ constant in the first place, if you control the class T and its implementation?
If you want to inhibit possible modifications from other developers that might work on the T class, then add plenty of documentation and comments about the values not being allowed to be modified. Then if someone modifies the values of a_ or b_ anyway, then it's their fault for making possibly breaking changes. Good code-review practices and proper version control handling should then be used to point out and possibly blame wrongdoers.
Before describing the answer, I'd first suggest you to re-think your interface. If there's an expensive operation, why don't you let the caller be aware of it and allow them to cache the result? Usually the design forms around the calculations and abstractions that are worth keeping as a state; if it's expensive and reusable, it's definitely worth keeping.
Therefore, I'd suggest to put this to the public interface:
struct ExpensiveResult
{
int expensive;
ExpensiveResult(int n)
: expensive(n*n*n - 1)
{}
};
class T
{
private:
const int a;
const int b;
T(const ExpensiveResult& e)
: a(ka * e.expensive)
, b(kb * e.expensive)
{}
};
Note that ExpensiveResult can be directly constructed from int n (ctor is not explicit), therefore call syntax is similar when you don't cache it; but, caller might, at any time, start storing the result of the expensive calculation.
It's pretty easy to modify the const ints in your object as a result of a significant change in c++20. The library function construct_at and destroy_at have been provided to simplify this. For your class, destroy_at is superfluous since the class contains no members that use dynamic memory like vector, etc. I've made a small modification, added a constructor taking just an int. Also defined an operator= which allows the objects to be manipulated in containers. You can also use construct_at to decrement a_ and b_ in your operator-- method. Here's the code:
#include <iostream>
#include <memory>
namespace {
constexpr int initializer{ 3 };
constexpr int ka{ 10 };
constexpr int kb{ 25 };
class T {
private:
int value;
const int a_{};
const int b_{};
public:
T(int n);
T(int n, int a, int b);
T(const T&) = default;
inline int operator()() const { return value; }
inline int a() const { return a_; }
inline int b() const { return b_; }
int& operator--();
T& operator=(const T& arg) { std::construct_at(this, arg); return *this; };
};
T::T(const int n, const int a, const int b) : value{ n - 1 }, a_{ a }, b_{ b } {}
T::T(const int n) : value{ n - 1 }
{
// The integer expensive
// + is to be computed only once and,
// + after the T object has been constructed,
// is not to be stored.
// These requirements must be met without reliance
// on the compiler's optimizer.
const int expensive{ n * n * n - 1 };
std::construct_at(this, n, ka*expensive, kb*expensive);
}
int& T::operator--()
{
// implement decrements
//--a_; --b_;
const int a_1 = a_ - 1;
const int b_1 = b_ - 1;
std::construct_at(this, value, a_1, b_1);
return value;
}
}
int main()
{
T t(initializer);
std::cout << "before decrement, t() == " << t() << "\n";
--t;
std::cout << "after decrement, t() == " << t() << "\n";
std::cout << "t.a() == " << t.a() << "\n";
std::cout << "t.b() == " << t.b() << "\n";
return 0;
}
Output:
before decrement, t() == 2
after decrement, t() == 1
t.a() == 259
t.b() == 649

Is there a technical implementation in c++, the modification of struct members is to modify the bound data, and this binding relationship is dynamic?

For example, if I have global variables:
int a;
int b;
I define that I can return a struct, I hope the members of the structure are bound to the global variables, and my modification to the members of the structure is to modify the global a, b. The code like:
struct bind
{
int a;
int b;
}
Bind getBind()
{
Bind bind;
band to a; // could be other variable, e.g. c
band to b; // could be other variable, e.g. d
return bind;
}
Note that it is not a simple reference, I may want to return the struct bound to c,d the next time I invoke getBind().
Background introduction:
collect data scattered around as a struct in a caller-unaware
way.
can return a const struct, caller can't modify its member
avoid modify member inconsciently by copy obj
I'm very puzzled, for the underlying language of C++, this should be easy to implement, but there seems to be no such funcation. Maybe I don't know, I hope so and get the answer here.
You can use references:
#include <iostream>
int a,b,c,d;
struct Bind {
int& ref1;
int& ref2;
};
Bind getBind(bool flag){
if (flag) return {a,b};
else return {c,d};
}
// ... or ...
Bind getBind(int& a,int& b){
return {a,b};
}
int main() {
auto x = getBind(true);
x.ref1 = 42;
x.ref2 = 101;
auto y = getBind(false);
y.ref1 = 0;
y.ref2 = 1;
auto z = getBind(a,b);
std::cout << z.ref1 << " " << z.ref2 << "\n";
auto w = getBind(c,d);
std::cout << w.ref1 << " " << w.ref2 << "\n";
}
Output:
42 101
0 1
However, it is not quite clear what you want to achieve. Global variables are better to be avoided in the first place and using reference as memebrs has certain implications, though if thats what you want then maybe its just fine.

Copying an object in C++

I would like to know if copying an object in the following manner is acceptable vis-a-vis copying the individual elements.
#include <iostream>
using namespace std;
class abc{
public:
abc(int a = 10, int b = 5);
abc(const abc &obj, int b = 10);
int ret_x() { return x; }
int ret_y() { return y; }
private:
int x;
int y;
};
abc::abc(int a, int b)
: x(a),
y(b)
{
}
abc::abc(const abc &obj, int b)
{
if (this != &obj) {
*this = obj; -----> Copying the object
}
y = b;
}
int main()
{
abc a1;
cout << "A1 values: " << a1.ret_x() << "\t" << a1.ret_y() << endl;
abc a2(a1, 20);
cout << "A2 values: " << a2.ret_x() << "\t" << a2.ret_y() << endl;
return 0;
}
Edit:
Use case:
The issue is that object a1 is auto-generated and hence any newly introduced members in the class could not be updated. I could provide a member function to update the new members, sure, but wanted to explore this option.
The code works fine, but is the method correct?
Thanks!
As chris noted already in the comments, you are creating a completely new object. How would you want to get this passed into the constructor? Well, actually, you could perhaps via placement new:
abc a;
abc* b = new(&a)abc(a);
But this is a such an exotic case that I would not consider it, I even dare to claim someone using advanced stuff such as placement new should know what he is doing... So leave out the if-check.
In your special case, it seems OK, as no data exists that might require deep copying. Be aware, though, that you are assigning the member b twice. Not really critical with int, but on larger objects (std::string, std::vector, ...) which do deep copies this gets more and more questionable.
With C++11, though, I would prefer constructor delegation:
abc::abc(const abc& obj, int b)
: abc(obj) // copying here
{
y = b;
}
This does not solve, however, the double assignment problem. To be honest, this might not always be a true problem, in many cases the compiler might optimise the first assignment away (especially in the int case of our example). But on more complex data types (possibly already std::string), I wouldn't feel comfortable relying on the compiler detecting obsolete assignment...
Be aware that you might get into trouble if you have resources managed internally:
struct abc
{
int* array;
abc() : array(new int[7]) { }
~abc()
{
delete[] array;
}
}
Not providing an appropriate assignment operator or copy constructor – depending on the implementation variant, yours (assignment) or mine (constructor delegation) – doing the necessary deep copy will result in multiple deletion of the same data (undefined behaviour!). Following the rule of three (or more recently, rule of five), you most probably will need both anyway. You might consider the copy and swap idiom idiom then.
Finally a trick to avoid double assignment:
abc(abc const& other)
: abc(other, other.y)
{ }
abc(abc const& other, int y)
: x(other.x), y(y)
{ }

c++ assigning dynamic struct

I really want to do the following:
(sorry about syntax, I have no idea how this is done)
struct Data {
int var = 5;
} data;
struct Data2 {
var;
} data2;
data2.var = data;
cout << data2.var.var; //prints 5
Basically I want to have a dynamic struct variable in a struct that can be given any struct as value and access it through the mains struct.
Please be nice. I really don't know how to explain it better and I really want to do this and been reading a lot yet haven't found any methods to do this.
Ps.
I DON'T want to do the following:
struct Data {
int var = 0;
} data;
struct Data2 {
data;
} data2;
I want it to be dynamic, that is, that I can change it any time during the program. Thank you.
Conceptually, you may (?) be asking about references:
#include <iostream>
int main() {
int x = 10;
int & xref = x;
std::cout << xref << "\n";
x = 20;
std::cout << xref << "\n";
}
That will print:
10
20
Underlying a reference is essentially a pointer, but it is one which can never be null...and notationally you don't have to "dereference" it. Were you using pointers, the above would look like:
#include <iostream>
int main() {
int x = 10;
int * xptr = &x;
std::cout << *xptr << "\n";
x = 20;
std::cout << *xptr << "\n";
}
Here they are applied to your example with minimal changes:
#include <iostream>
struct Data {
int var;
};
struct Data2 {
Data & var;
};
int main()
{
Data data = {5};
Data2 data2 {data};
std::cout << data2.var.var << "\n";
data.var = 10;
std::cout << data2.var.var << "\n";
return 0;
}
Odds are "this isn't what you actually want" (you shouldn't usually be exposing member variables, much less member variables that are references to other variables). And they shouldn't be all named var. Etc.
Still, references are an integral part of the language and worth learning about.
(Note: for brevity, you may omit the return 0;...only from main. That's assumed, and legal in the standard; and you may omit its arguments. But you must return an int.)
You can use void pointer like this:
#include <iostream>
using namespace std;
struct Data
{
int var;
}data;
struct Data2
{
void *var;
}data2;
int main()
{
data.var = 5;
data2.var = &data;
cout<<((Data *)data2.var)->var<<endl;
return 0;
}
But it is not safe because somtimes you can't make sure that other struct has member called var which may cause unexpected result.
Basically I want to have a dynamic struct variable in a struct that
can be given any struct as value and access it through the mains
struct.
You can emulate the effect of dynamic typing by using polymorphism. The following is a test example for your case.
#include <iostream>
using namespace std;
struct BaseDataStruct
{
virtual int get_data() = 0;
};
struct Data : BaseDataStruct
{
int var = 5;
virtual int get_data() { return var;}
} data;
struct Data2 {
BaseDataStruct* var;
} data2;
int main()
{
data2.var = &data;
cout<<data2.var->get_data();
return 0;
}
By using BaseDataStruct as an interface base class for all the structs which Data2::var is expected to point to you can achieve the "dynamic typing" behavior you are trying to get.
Note: I changed the Data2::var a to pointer to avoid object slicing. You will need to jump through many hoops to avoid that if you want to have it by value.
TL/DR: C++ is statically typed, so what you want to do is against the spirit of thr language. However, if you really have to you can use void* in C and boost::any in C++
Now a bit more about void* (to know more about boost::any refer to its documentation).
void* is a pointer that holds a raw address in memory. This value beyond this address could be everything: float, int or your struct. Here is the usage example.
struct Data {
int var = 5;
};
struct Data2 {
void* var;
};
int main() {
Data data;
Data2 data2;
data2.var = (void*)(&data);
cout << ((struct Data*)data2.var)->var << endl;
}
If the concept of pointers is new for you you can read about it here. Void pointers are explained there as well.