I have a class that should, as its input data, either use a reference to external data (without copying), or create the data itself based on other input. I prefer using references (to avoid dereferencing, since the data are matrices) and ended up with the following structure (simplified):
#include <iostream>
#include <vector>
using namespace std;
using VectI = vector<int>;
class A {
VectI x0;
VectI const & x = x0;
public:
A(VectI const & extX) : x(extX) {} // referencing existing external data
A(int i) { x0.push_back(i); x0.push_back(i*i); } // create from other data
void show_x()
{ cout << "x ="; for (auto&& i : x) cout << " " << i; cout << endl; }
};
int main() {
VectI myX = {1, 2, 3};
A a(myX); a.show_x(); // a references myX
A b(2); b.show_x(); // b creates its own data based on i=2
return 0;
}
The example works:
x = 1 2 3
x = 2 4
but are there any potential problems with this approach?
In particular, is the fact that I am changing x0 that is referenced by the const vector x 'legal' C++, or is it something that other compilers might complain about?
Also, can I be sure that the first constructor avoids copying data?
This is fine in the C++11 standard but your code is very brittle.
In particular the compiler generated copy and move constructors and the assignment operator will not work correctly, so you'll have to build your own.
You might also encounter dangling references: remember that the object lifetime extension due to a const reference is not transitive. The behaviour on using A(VectI const & extX) with an anonymous temporary is undefined.
Using a pointer to VectI - perhaps even a std::unique_ptr to a VectI along with a concept of ownership might be a safer way to go.
Related
I am new to C++ and get confused about what goes on under the hood when a class method returns a reference to a member variable that is raw data (rather than a pointer or a reference). Here's an example:
#include <iostream>
using namespace std;
struct Dog {
int age;
};
class Wrapper {
public:
Dog myDog;
Dog& operator*() { return myDog; }
Dog* operator->() { return &myDog; }
};
int main() {
auto w = Wrapper();
// Method 1
w.myDog.age = 1;
cout << w.myDog.age << "\n";
// Method 2
(*w).age = 2;
cout << w.myDog.age << "\n";
// Method 3
w->age = 3;
cout << w.myDog.age << "\n";
}
My question is: what happens at runtime when the code reads (*w) or w-> (as in the main function)? Does it compute the address of the myDog field every time it sees (*it) or it->? Is there overhead to either of these two access methods compared to accessing myDog_ directly?
Thanks!
Technically, what you are asking is entirely system/compiler-specific. As a practicable matter, a pointer and a reference are identical in implementation.
No rational compiler is going to treat
(*x).y
and
x->y
differently. Under the covers both usually appears in assembly language as something like
y(Rn)
Where Rn is a register holding the address of x and y is the offset of y into the structure.
The problem is that C++ is built upon C which in turn is the most f*&*) *p programming language ever devised. The reference construct is a work around to C's inept method of passing parameters.
This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 4 years ago.
Take the following example:
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
class Foo{
public:
Foo(){
cout << "Constructing the default way..." << endl;
this->num = (int*)malloc(sizeof(int));
}
Foo(int a){
cout << "Using a custom constructor..." << endl;
this->num = (int*)malloc(sizeof(int) * a);
}
~Foo(){
cout << "Destructing..." << endl;
free((void*)num);
}
int* num;
};
int main()
{
vector<Foo> objects(5);
for(Foo& v : objects) printf("%x0x\n", v.num);
cout << "\n---------------\n";
cout << "END OF PROGRAM!\n";
cout << "---------------\n\n";
return 0;
}
Creating the vector by passing it an initial count of objects creates every single object individually, hence, all of them have their num at different addresses and their destructors are called at the end of the program.
However, if I want to create the vector by giving it a custom constructor like vector<Foo> objects(5, Foo(5)); (This is only my guess) a temporary object is constructed and then copied to every object in the array. Effectively, this makes every single object in the vector have their num pointer point to the same memory. Plus that memory gets freed when the initialization is finished and then every single object becomes useless.
How do I go around this without making the custom constructor into a new Init(int) function and running it on every single object in the vector? (Of course changing malloc into realloc).
You could solve your problem with a vector of unique_ptr's to the Foo objects.
class Foo
{
public:
Foo(int i) {}
// ...
};
#include <algorithm>
#include <vector>
auto main() -> int
{
std::vector<std::unique_ptr<Foo>> foos(100);
std::generate(foos.begin(), foos.end(), []() { return std::make_unique<Foo>(5); });
}
However, you don't want to do this because otherwise you would have to go the extra indirection with the unique_ptr when calling anything on a vector's Foo object.
As others have already suggested, you should store Foo's int members in a vector. Then you can just reserve the space in the vector and emplace_back (construct) your Foo objects directly in the vector of Foo's.
#include <vector>
class Foo
{
public:
Foo() {}
Foo(int i) : ints(i) {}
private:
std::vector<int> ints;
};
namespace
{
constexpr auto NumberOfFoos = 100;
}
auto main() -> int
{
std::vector<Foo> foos;
foos.reserve(NumberOfFoos);
for (auto i = 0; i < NumberOfFoos; ++i) {
foos.emplace_back(10);
}
}
Regarding your code, you might want to have a look at these additional sources and answers (as already suggested by other comments):
Rule of three
Stop using std::endl
Why is “using namespace std” considered bad practice?
Two problems preventing a solution.
1) You need to implement your custom copy and assignment operators to do the deep copying since the default shallow copy (as you point out) doesn't do the right thing.
2) You need to let the object remember how large an array you are allocating for the copy/assignment implementations to work.
Let's look at the following C++ code:
#include <iostream>
int main()
{
int z = 2;
class A {
public:
const int & x;
A(const int & x) : x(x) {}
void show(){
std::cout << "x=" << this->x << std::endl ;
}
} a(z);
a.show();
z = 3;
a.show();
}
The program prints: 2 and 3
It clearly shows that while inside class A x can't be modified, it merely means it's read only, because I can change it's value from outside.
Of course I can make it a copy stored inside class A, but I'm wondering if there is (or if there is a proposal?) of a way to say to class A that the member x will be truly constant instead of merely read only, with the meaning of a promise that the external code won't change it ?
To my eyes it looks like something related to the meaning of the C restrict keyword, but I've not heard of any such C++ feature yet. Do you ?
Constness is an attribute of the actual variable.
The term const int& x simply means "x is a reference to an int which it will not modify" and of course the compiler enforces this.
If you want the actual variable to which x refers to be const, simply declare it so:
#include <iostream>
int main()
{
const int z = 2; // declared const. Nothing may ever modify it
class A {
public:
const int & x;
A(const int & x) : x(x) {}
void show(){
std::cout << "x=" << this->x << std::endl ;
}
} a(z);
a.show();
z = 3; // this is a logic error, caught by the compiler.
a.show();
}
compiling correctly produces the error:
./const.cpp:41:7: error: read-only variable is not assignable
z = 3;
~ ^
1 error generated.
You're looking for D's immutable keyword, which was introduced as a new concept in that language precisely because, unfortunately, the answer is no: it does not exist in C++.
Constness in C++ does not mean immutability, but that the variable in question is read-only. It can still be modified by other parts of the program. I understand your question as to whether it's possible to enforce true immutability in a called function without knowing what the caller is doing.
Of course you can create a template wrapper class which accomplishes the task:
template <typename T>
class Immutable
{
public:
template <typename ...Args>
Immutable( Args&&...args )
: x( std::forward<Args>(args)... )
{}
operator const T &() const
{
return x;
}
private:
const T x;
};
As long as you do not reinterpret_cast or const_cast you will have truly immutable objects when you wrap them with Immutable<T>.
However, if you have a constant reference to some object, there is no way to tell, if some other part of the program has a non-constant access to the object. In fact, the underlying object might be a global or static variable, that you have read-only access to, but functions you call might still modify it.
This cannot happen with Immutable<T> object. However, using Immutable<T> might impose an extra copy operation on you. You need to judge yourself if you can live with that and if the cost justifies the gain.
Having a function require an const Immutable<Something> & instead of const Something & as an argument affects the calling code. A copy operation might be triggered. Alternatively, you can ask for an Immutable<Something> & without the const. Then no accidental copies will be triggered, but the calling code must pass a reference to Immutable<Something> object. And rightly so, because if the caller received a const & as an argument then the caller does not know, whether the object might get modified by someone else in the program. The caller has to create the object itself or require an immutable object to be passed to it as a reference.
Your original question
Here's your original problem with Immutable<int> & instead of const int &.
#include <iostream>
int main()
{
Immutable<int> z = 2;
class A {
public:
const Immutable<int> & x;
A(Immutable<int> & x) : x(x) {}
void show(){
std::cout << "x=" << this->x << std::endl ;
}
} a(z);
a.show();
//z = 3; // this would fail
a.show();
}
An other example
Here's how it works: If you write
void printAndIncrementAndPrint( int & i1, const int & i2 )
{
std::cout << i2 << std::endl;
++i1;
std::cout << i2 << std::endl;
}
int main()
{
int i = 0;
printAndIncrementAndPrint( i, i );
}
then it will print
0
1
into the console. If you replace the second argument of printAndIncrementAndPrint() with const Immutable<int> & i2 and keep the rest the same, then a copy will be triggered and it will print
0
0
to the console. You cannot pass and Immutable<int> to the function and a int & to the same underlying data without breaking the typesystem using const_cast or reinterpret_cast.
I think this is a design problem for the programmers, not the language. A const variable means for any user of that variable, they should not change the value of that variable. Our compiler is smart enough to help us make sure of that. So A is a user of z and if you want A know that A::x references to a const variable, then you should make z a const int. The const reference is just to keep the contract between the user and the provider.
Here's an extremely basic example of my question.
#include <iostream>
#include <string>
using namespace std;
int x;
void test(int x) {
x += 3;
cout << x << endl;
}
int main() {
test(x);
cout << x << endl;
return 0;
}
the output is:
"3" (new line) "0"
How can I specify inside of the "test()" function that I want the class's 'x' variable to have the 3 added to it instead of the temp variable inside of the function?
In java you specify that you're dealing with the function/method's variable by using '"this". Is there a similar way to do this in C++?
In your case you can use :: to specify to use global variable,
instead of local one:
void test(int x) {
::x += 3;
cout << ::x << endl;
}
And it is not class member or so on just global and local.
In the C++ language, create a class or struct and you can use this->x the same as this.x in the Java language.
First of all, thank you for stating that you come from Java. This will help us a lot in terms of helping you!
Now, let's analyze your code
#include <iostream>
#include <string>
using namespace std;
Including some headers, using the std namespace (not recommended, BTW), everything's okay here.
int x;
You declare a variable named x of type int at global scope, with an initial value of zero (this only applies to objects at global scope!).
void test(int x) {
x += 3;
cout << x << endl;
}
You declare a function test that takes a parameter x of type int and returns void (a.k.a: nothing). The function increments the value of its intenral x variable by 3, then prints that to standard output by means of std::cout. Just to be clear, once you declare the int x parameter, it "hides" the int x at global scope, thus if you want to access the later, you have to use another way (see below).
int main() {
test(x);
cout << x << endl;
return 0;
}
You declare the special main function, taking no parameters and returning int. The function calls test with the global int x as argument, then prints the value of the global x to the standard output by means of std::cout, and finally returns zero, indicating successful execution.
Now, you have a big misconception, that you can attribute to the single-paradigm design of the Java language. In Java, there's no concept of "global functions", not to even say there are no "functions" at all. You only have "classes" with "methods".
In C++, this is not the case. The C++ language is a multi-paradigm one; it allows you to do imperative programming, structured programming, object-oriented programming, and even functional programming (you're not expected to have understood that last sentence completely)! When you declare anything without specifying an scope, it's said to lie in the global scope. The global scope can be accessed by anything, anywhere. In the example you presented there are no classes involved!
In the global scope, something like void test(int) is not a method, but a function. There's no class "owning" that function; let's say it's of "everyone" ;). A function is just a block of code that you can reuse by giving it arguments, if the function has them at all. In C++, you use classes to encapsulate data and corresponding code in a single "packed" black-box entity, not for, well, anything, like in Java.
Now, (this is somewhat like Java, but be careful!), when you pass a "plain" object, such as an int or something more funky and complex like std:: (you were not expected to understand that...) to a function, that function gets a copy of that object. The int x in test is not the same as the one main passed to it. If you assign to it inside test, you'll notice main "sees no difference". In Java, this applies too, but only to the fundamental types like int, but in C++ it does for all types.
If you want to be able to change the variable you got, just use references. You get a reference of any type T by typing T&. So, if you assign to a int& x inside the now modified test, main will "see" all changes.
Finally, there's the :: operator. It's used to access stuff in some scope from, well, other scopes. It has the form namespace-or-class::stuff. So for example, std::cout refers to identifier cout in namespace std. There's a special case: if the left operand is not given, :: accesses the global scope. This is useful whenever you "hide" something from the global scope. So, for example, in test, you could say ::x, and that would refer to the x in the global scope!
void test(int x) {
// ...
::x += 123;
}
Edit: If you're curious, you can take a glance at how classes in C++ work with this (I won't explain it, because that's off-topic)...
#include <iostream>
int x = 0;
class MyClass {
private:
int x;
public:
MyClass() : x(0) {}
void test(int x) {
this->report(x);
std::cout << "Doing some magic...\n";
this->x += x;
this->report(x);
}
void report(int x) {
std::cout << "this->x = " << this->x << '\n';
std::cout << "x = " << x << '\n';
}
};
int main() {
MyClass c;
c.report();
x += 123;
c.test(x);
x += 456;
c.test(x);
c.report();
}
I have inherited my class from std::vector. Now I want to overload the []-operator.
When I try to assign a new value to my vector, e.g. v[0]=5, I should receive the message OK.
This is my code (I know, that makes no sense, I'm just playing around):
#include<vector>
#include<iostream>
class Vec : public std::vector<int> {
public:
int operator[](int);
};
int Vec::operator[](int i) {
(*this)[i] = i;
std::cout << "OK";
return 123;
}
int main() {
Vec v;
v[0]=5;
}
Unfortunately I get the following error:
In member function ‘int Vec::operator[](int)’:
error: lvalue required as left operand of assignmen
In function ‘int main()’:
error: lvalue required as left operand of assignment
This particular error is caused because you are not returning an lvalue, generally defined as something that can appear to the left of an assignment, such as v[0] = 5;. You have more problems as pointed out in the other answers but this is the specific issue you face with that error message (a).
The correct specification for overloading the index operator is:
int& operator[] (const int nIndex);
You have to return a reference to the item (so it can be modified) if you want to treat it as an lvalue. The following code shows a fix, although obviously all array indexes map to the same value in this simplified case:
#include <vector>
#include <iostream>
class Vec : public std::vector<int> {
public:
int& operator[] (int); // <-- note the '&'
private:
int xyzzy;
};
int& Vec::operator[] (int idx) { // <-- note the '&'
std::cout << "OK\n";
return xyzzy;
}
int main () {
Vec v;
v[0] = 5;
v[1] = 6;
std::cout << v[22] << '\n';
return 0;
}
The output of this is:
OK
OK
OK
6
In reality, you wouldn't map all indexes to the same value, the code above is simply to illustrate the correct function signature. I haven't bothered to give a more complete example since subclassing classes with non-virtual destructors regularly leads to problems in non-trivial code (b).
(a) It's not usually considered a good idea to subclass std::vector since the destructor isn't virtual, so you can get into trouble when trying to destroy an object polymorphically.
You're probably better off using a has-a relationship (where your class contains a vector) rather than an is-a relationship (where you inherit).
That unfortunately means you may have to create a lot of pass-through methods from your class to the underlying vector (although only the ones you need) but it will solve the problem with the destructor.
(b) See (a) :-)
You'd need to return a reference to your element - however note that even if you did, you'd run into inifinite recursion - your operator[] calls itself.
Either way - inheriting from std::vector isn't a good idea. Use composition instead.
The code below illustrates how to call the operator[] from the vector base class....
#include <iostream>
#include <vector>
struct Vec : std::vector<int>
{
int& operator[](int n)
{
std::cout << "operator[](" << n << ")\n";
return std::vector<int>::operator[](n);
}
};
int main()
{
Vec v;
v.push_back(10);
v.push_back(20);
v[0] += 5;
std::cout << v[0] << ' ' << v[1] << '\n';
}
Output when I run it:
operator[](0)
operator[](1)
operator[](0)
15 20
Don't take all this talk about "do not inherit from std::vector" too seriously: you have to go out of your way to delete a dynamically allocated Vec using a std::vector<int>*, or do an accidental by-value slicing copy - and even then it'd probably only bite you if you had added data members. You should make sure you understand those risks then make your own assessment, but for small utility programs etc. it's productive to inherit from such classes sometimes....