Is it okay to use object pointer to overload assignment operator? - c++

Suppose we want to implement a Complex Number class:
#include <iostream>
using namespace std;
class Complex{
public:
double real;
double imag;
Complex();
Complex(double _r, double _i)
:real(_r),imag(_i){}
const Complex* operator = (const Complex*);
};
Normally to overload assignment operator we would pass a const reference as parameter, but why can't we pass a pointer instead, like this?
const Complex* Complex::operator = (const Complex* cp){
real = cp->real;
imag = cp->imag;
return this;
}
int main(){
Complex c1(1,2), c2(3,4), c3(5,6);
Complex *pc = &c3;
c1 = c2 = pc;
cout<<"c1 = "<<c1.real<<"+"<<c1.imag<<'i'<<endl;
cout<<"c2 = "<<c2.real<<"+"<<c2.imag<<'i'<<endl;
cout<<"c3 = "<<c2.real<<"+"<<c2.imag<<'i'<<endl;
return 0;
}
The above code runs and give the answer just as I expected: all three complex numbers yield 5+6i.
I know this approach is rather unorthodox, but it seems to work as well. I'm wondering why our teacher strongly recommended us to use reference for assignment? Thanks a lot guys!

you can do that if you wish. But it's not a good idea.
Usually you'd imagine that an assign takes an object of the same type:
/*typeA*/ A = /*typeA*/ B;
a more real problem is that pointers are ints. You would assume that the code:
Complex c = 5;
sets a complex {5, 0}, instead it will segfault (some compilers will warn you that int->complex* conversion was probably not intended, but sooner or later it, one cast<> or another, it will happen)

Related

Copy vs ref benchmark: When are objects NOT passed in registers?

I heard that small objects are passed in CPU registers on function calls. I tried to search the maximum of when this is not anymore the case. I know that string_view is passed in registers. But what is the limit? I know this is architecture dependent, but it seems that even really large objects can be passed by registers. Compare the following:
(Check it out on Quickbench)
struct big_object
{
int a_;
double b_;
char c_;
long long d_;
bool e_;
int f_;
double g_;
char h_;
long long i_;
bool j_;
int k_;
double l_;
char m_;
long long n_;
bool o_;
};
big_object obj = {
.a_ = 2,
.b_ = 2.5,
.c_ = 'A',
.d_ = 1203912045891732283,
.e_ = false,
.f_ = 10,
.g_ = 15.5,
.h_ = 'D',
.i_ = 123123123,
.j_ = true,
.k_ = 10,
.l_ = 15.5,
.m_ = 'D',
.n_ = 123123123,
.o_ = true,
};
volatile int a;
volatile double b;
volatile char c;
volatile long long d;
volatile bool e;
volatile int f;
volatile double g;
volatile char h;
volatile long long i;
volatile bool j;
volatile int k;
volatile double l;
volatile char m;
volatile long long n;
volatile bool o;
int foo(big_object obj)
{
a = obj.a_;
b = obj.b_;
c = obj.c_;
d = obj.d_;
e = obj.e_;
f = obj.f_;
g = obj.g_;
h = obj.h_;
i = obj.i_;
j = obj.j_;
k = obj.k_;
l = obj.l_;
m = obj.m_;
n = obj.n_;
o = obj.o_;
return 1;
}
int foo_ref(big_object& obj)
{
a = obj.a_;
b = obj.b_;
c = obj.c_;
d = obj.d_;
e = obj.e_;
f = obj.f_;
g = obj.g_;
h = obj.h_;
i = obj.i_;
j = obj.j_;
k = obj.k_;
l = obj.l_;
m = obj.m_;
n = obj.n_;
o = obj.o_;
return 1;
}
static void Foo(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
foo(obj);
}
}
// Register the function as a benchmark
BENCHMARK(Foo);
static void FooRef(benchmark::State& state) {
// Code before the loop is not measured
for (auto _ : state) {
foo_ref(obj);
}
}
BENCHMARK(FooRef);
This compiles to exactly the same code and hence provide the same performance. I'm not an assembly pro, but I think I can see that a lot of registers are used to pass the object to the function. I know that there are even more physical CPU registers than logical ones, but does this mean that in any practical case, passing by reference is actually superfluous?
When function call is optimized out, when function is inlined, when you use pointers instead of objects and compiler decides that it's not worth copying, to name a few. There's no clear ruleset that compiler programmers have to follow other than C++ standard.
but does this mean that in any practical case, passing by reference is actually superfluous?
No it isn't, references are a semantic construct and not an optimization "trick", so treat them as such.
References are simply aliases to variables. Everything else is quite literally up to the compiler. One useful properly of mutable reference is that mutated object actually changes on the caller side too once the function returns.
Sure, you can also use a pointer to achieve same thing, but an even more useful property of reference is a guarantee that the object you will be accessing is valid, while a pointer is nullable.
Speaking of which, even pointers are treated more or less the same nowadays, just look at -findirect-inlining in GCC, in similar way, float* can be optimized out by a compiler to simply a direct float copy. I can't remember the name of this optimization, but I know for a fact that GCC at least used to have it. And if you have a function like float add(float* a, float* b), it will be inlined in most cases so it doesn't matter how you write it. It's simply a matter of choosing the most clear version.
Instead of worrying about things you don't understand, nor even need to, you should focus on semantics of your code. Let's be real, you're using a high level language like C++ instead of hand optimizing all ISA yourself is precisely because you want someone else to do hard work for you, so how come you don't trust them when that's the sole job they were given?
For example, it's pointless to take const& as parameter just to copy the object. If you want a copy of object in your function, then write so. Not only is this cleaner and more obvious to programmers that you will be copying, but it's clearer even to the compiler, which is also made by programmers. The fact that you benefit from certain optimizations is the only thing that's superfluous here. You're simply making it clear to anyone reading declaration that this object right there will be copied, that's all that matters. It doesn't matter how slow it is, you need to copy, so you copy.
Write code that's readable and understandable, you can worry about performance when you have a working program. If you can think of something "ingenious", the matter of fact is that compiler programmers thought of it before already.
And by the way, your benchmark doesn't benchmark anything. You're literally comparing identical code.
So like I already wrote before, do you want to copy the struct? Or simply reference something in it? That's the only thing that matters.

Overloaded assignment operator for copy/move operations?

I'm going over the basics of overloaded operators, specifically the assignment operator. I'm trying to understand the use of overloading in dictating copy and move behavior by following this:
operator overloading
I find the example they give to be quite unclear.
This is the basic code I've written so far to illustrate overloading. How can this code be edited to illustrated the use of overloading in customizing copy and move behavior?
class Distance
{
public:
int feet, inches;
Distance()
{
feet = 0;
inches = 0;
}
Distance(int f, int i)
{
feet = f;
inches = i;
}
auto operator=(Distance &D)->void //Use operator to perform additional operation (adding 100)
{
feet = D.feet + 100;
inches = D.inches + 100;
}
};
int main()
{
Distance D1;
D1.feet = 10;
D1.inches = 12;
Distance D2;
D2 = D1;
std::cout << D2.feet << std::endl;
}
You shouldn't use assignment operator like that (even if you can). Assignment operator with additional operation could be used for example for counting how many assignments was made. Altering data this way leads to confusion and human error during use of the interface. You expect the code to work in some way, in case of assignment operator, it is copying values. Just follow how built-in types work and implement your overloaded operators that way. You wouldn't multiply volumes for operator+(), right? That wouldn't make any sense.
Additional operation in this case could be e.g.:
static int assignmentCount = 0;
auto operator=(Distance &D)->void
{
feet=D.feet;
inches=D.inches;
std::cout << "Made assignment"; //Just some debug stuff
assignmentCount++; //Count assignments made
}
Don't forget, that you have put there void as return type, which disables you to do following D1=D2=D3, which could be useful in some cases. Returning reference to receiving value is common practice.
I recommend reading Professional C++ by Marc Gregoire, or one of Stroupstrup's books. My recent experience is, that online sources can lead to some sort of confusion and books are generally better for learning basics.

c++ changing implicit conversion from double to int

I have code which has a lot of conversions from double to int . The code can be seen as
double n = 5.78;
int d = n; // double implicitly converted to a int
The implicit conversion from double to int is that of a truncation which means 5.78 will be saved as 5 . However it has been decided to change this behavior with custom rounding off .
One approach to such problem would be to have your own DOUBLE and INT data types and use conversion operators but alas my code is big and I am not allowed to do much changes . Another approach i thought of was to add 0.5 in each of the numbers but alas the code is big and i was changing too much .
What can be a simple approach to change double to int conversion behaviour which impact the whole code.
You can use uniform initialization syntax to forbid narrowing conversions:
double a;
int b{a}; // error
If you don't want that, you can use std::round function (or its sisters std::ceil/std::floor/std::trunc):
int b = std::round(a);
If you want minimal diff changes, here's what you can do. Please note, though, that this is a bad solution (if it can be named that), and much more likely leaving you crashing and burning due to undefined behavior than actually solving real problems.
Define your custom Int type that handles conversions the way you want it to:
class MyInt
{
//...
};
then evilly replace each occurence of int with MyInt with the help of preprocessor black magic:
#define int MyInt
Problems:
if you accidentally change definitions in the standard library - you're in the UB-land
if you change the return type of main - you're in the UB-land
if you change the definition of a function but not it's forward declarations - you're in the UB/linker error land. Or in the silently-calling-different-overload-land.
probably more.
Do something like this:
#include <iostream>
using namespace std;
int myConvert (double rhs)
{
int answer = (int)rhs; //do something fancier here to meet your needs
return answer;
}
int main()
{
double n = 5.78;
int d = myConvert(n);
cout << "d = " << d << endl;
return 0;
}
You can make myConvert as fancy as you want. Otherwise, you could define your own class for int (e.g. myInt class) and overload the = operator to do the right conversion.

Operator Overloading + c++

So I'm supposed to write a program that has num and denom as integer data members of the Fractions class. I'm also supposed to have member functions that can display an object's data values and an overloaded operator function for +. My program says my subscripted items are an invalid data type, but I don't know how to allow for the second fraction without them. Does anyone know how I can fix this?
My code is the following:
#include <iostream>
#include <cmath>
using namespace std;
int a, b, c;
class Fractions
{
private:
int num;
int denom;
public:
Fractions(int=1, int=1);
void operator!(void) const;
Fractions operator+(const Fractions&) const;
};
Fractions::Fractions(int n, int d)
{
if( d != 0)
num= n;
denom= d;
}
Fractions Fractions::operator+(const Fractions& f) const
{
a= num/denom;
b= num[1]/denom[1];
c= a + b;
c= (num * denom[1]+ denom * num[1])/(denom * denom[1]);
return c;
}
int main()
{
return 0;
}
You've declared num and denom as int but in your function you're treating them like arrays: b= num[1]/denom[1];
That won't work. What is it you want to do with this line b= num[1]/denom[1];? Is the idea to divide by the value of the fraction you're adding? If so maybe what you want is: b = f.num/f.denom;
My algebra isn't the best, but I can't recall using division when adding fractions, but that might be another question (or I might have it wrong).
The most immediate issue that is causing the error you're specifying is caused by trying to do:
b= num[1]/denom[1];
You initialized b, num and denom as an int, not an integer array. But you are trying to access an element of num and denom as if they were arrays.
Either initialize an array of integers for each or dropping the access operator for them will fix the error, but I don't believe it will give you your desired result.
The way you're overloading the '+' operator will not work. Since you have the '+' operator as a member, the object of that class becomes the left hand side of the operator, and what you are passing (const Fractions& f) becomes the right hand side.
You are not using the 'f" variable that you pass in at all, nor are you affecting that instance's members. All you are doing is changing some global variables that really aren't necessary. I recommend you read up on operator overloading since it seems you don't quite understand how it works.

operator function in C++ and compile error relating to it

there are probably several ways I will expose my ignorance with this question :)
First, I think this is C++ code, but the extension of the file is .C (so maybe it is C?)
Anyway, I am trying to compile a program called Sundance (Sentence UNDerstanding ANd Concept Extraction) which is a Natural Language Processing tool. The compile error I get relates to the following:
// This class is used internally to keep track of constituents that are
// potential subjects for clauses during clause handling.
class PotentialXP {
public:
Constituent* XPPtr;
unsigned int Distance;
unsigned int ClauseIndex;
unsigned int ConstIndex;
PotentialXP() {
XPPtr = 0;
Distance = 0;
ClauseIndex = 0;
ConstIndex = 0;
};
operator int() const {
return (int)XPPtr;
};
void Set(Constituent* w,
unsigned int x,
unsigned int y,
unsigned int z){
XPPtr = w;
Distance = x;
ClauseIndex = y;
ConstIndex = z;
};
};
The error is "cast from ‘Constituent* const*’ to ‘int’ loses precision"
and relates to the lines:
operator int() const {
return (int)XPPtr;
};
I understand why I get an error. XPPtr is of type Constituent*, so how can it be converted to an integer? Can anyone figure out what the author of the code wants to do here, and how I might rewrite this line so it compliles? What is an operator function (if that's what you call it) for?
Any advice much appreciated!
That compiles fine for me. You are on a 64-bit machine, where size_t is larger than int.
Explanation: you can historically convert a pointer an int
struct Foo {};
int main ()
{
Foo * f = new Foo ();
std :: cout << (int)f; // Prints 43252435 or whatever
}
If you want an integer which is the same size as a pointer, use size_t or ssize_t.
And why on earth are you writing operator int() like that anyway? Do you want operator bool() to test for validity? In which case a function body of return NULL != XPPtr would be better style -- clearer, at least.
The line operator int() const states a how your object can be cast to int.
The Constituent* can be cast to int because both types are usually the same size. I do not think that this is what the programmer intended, since the raw pointer value is of no semantic use. Maybe there should be a field lookup? E.g:
operator int() const {
return (int)XPPtr->somevalue;
};