I'm trying passing the reference of array to class object by constructor, and operating the items in that object.
But, I'm afraid that these items in array are changed just after reaching at the beginning of MySort::sort() below. (not changed before entering MySort::sort())
#include <iostream>
#include <utility>
#include <array>
using namespace std;
template <typename T>
struct MySort
{
T &_n;
size_t _s;
public:
MySort(T n) : _n(n)
{
_s = _n.size();
}
void sort()
{
for (size_t i = 0; i < _s - 1; i++)
{
for (size_t j = i + 1; j < _s; j++)
{
if (_n[i] > _n[j])
std::swap(_n[i], _n[j]);
}
}
cout << "teste" << endl;
}
friend ostream &operator<<(ostream &ost, const MySort &c)
{
for (size_t i = 0; i < c._s; i++)
ost << c._n[i];
return ost;
}
};
int main(int argc, const char **argv)
{
array<int, 5> numbers{2, 5, 1, 7, 3};
MySort<array<int, 5>> bubble{numbers};
bubble.sort();
cout << bubble << endl;
return 0;
}
In the case of passing array by copy, It works correctly.
Thank you for your attention.
The constructor
MySort(T n) : _n(n)
{
_s = _n.size();
}
Here you set _n to reference a input object which will get destroyed upon leaving the constructor. This is plain UB.
To fix it write
MySort(T& n) : _n(n)
{
_s = _n.size();
}
In the constructor MySort(T n), you are making a copy of the array, then storing a reference to the copy, but then the copy goes out of scope, so you have a dangling reference.
If you want to use a reference, you should pass a reference to the original object, MySort(T &n), and make sure that the original object is always in scope during the lifetime of the MySort object.
Related
Consider the following code .
#include <iostream>
#include <map>
class A{
public:
int m_id;
int m_x;
int m_y;
A() = default;
A(int i, int j, int k) : m_id(i), m_x(j), m_y(k){}
};
void add(const A& a, std::map<int,A>& m){
m[a.m_id] = a;
}
void modify(std::map<int,A>& m){
for(auto& x : m){
x.second.m_x*=10;
x.second.m_y/=10;
}
}
void print(std::map<int,A>& m){
for(const auto& x : m){
std::cout << x.first << " : (" << x.second.m_x << ',' << x.second.m_y << ")\n";
}
std::cout << '\n';
}
int main(int argc, char const *argv[])
{
std::map<int,A> m;
A a(1,10,100);
add(a,m);
print(m);
{
A b(2,10,200);
add(b,m);
print(m);
}
modify(m);
print(m);
return 0;
}
I am creating a std::map of objects of type A. In add, I add an object to the std::map by using a const reference to that object. In modify, I am modifying values of std::map. In print, I am printing the map. Basically accessing the elements.
I add b in a different scope to test if it I get a memory error.
The code works correctly.
My question is, is std::map with [] operator creating a new non const copy of the object ? Also, std::vector::push_back works fine. Does push_back also create a copy. I am not calling emplace.
Yes, a new object will be constructed as the element of std::map. To be precise, in m[a.m_id] = a;, if the key (i.e. a.m_id) does not already exist, a value-initialized A will be constructed as the new element of m firstly, then m[a.m_id] returns the reference to value of the new element; which is copy-assigned from a via the copy-assignment operator of A later.
If the key (i.e. a.m_id) already exists, m[a.m_id] just returns the reference to value of the existed element; which is copy-assigned from a then.
If I have a class with members like this:
class MyClass {
public:
void set_my_vector() {
for (int ind = 0; ind < 3; ++ind) {
my_vector.push_back(new MyStruct(i, i*2));
}
}
private:
struct MyStruct {
int num_a;
int num_b;
MyStruct(int i, int j) : num_a(i), num_b(j) {}
};
std::vector<MyStruct*> my_vector;
};
Do I need to write the rule-of-five functions, or will std::vector take care of deep copying and deleting the elements allocated on the heap?
EDIT:
The following code uses default copy constructor, so I assume that after I copy my_class1 object into my_class2 object, the elements of my_class1.my_vector and my_class2.my_vector will be the same, because the MyStruct pointers were copied, but not the data itself. However, the output shows that they are not the same. You can run the code here: https://onlinegdb.com/S1pK9YE4v
#include <iostream>
#include <vector>
class MyClass {
public:
void fill_my_vector(int i, int j) {
my_vector.clear();
for (int ind = 0; ind < 3; ++ind) {
my_vector.push_back(new MyStruct(i, j));
}
}
void print () {
for (int ind = 0; ind < 3; ++ind) {
std::cout << my_vector[ind]->int1 << ", " << my_vector[ind]->int2 << std::endl;
}
std::cout << std::endl;
}
private:
struct MyStruct {
MyStruct (int i, int j) :
int1(i), int2(j)
{}
int int1;
int int2;
};
std::vector<MyStruct*> my_vector;
};
int main()
{
MyClass my_class1;
my_class1.fill_my_vector(42, 43);
std::cout << "my_class1: " << std::endl;
my_class1.print();
MyClass my_class2 = my_class1;
my_class2.fill_my_vector(12, 13);
std::cout << "my_class2: " << std::endl;
my_class2.print();
std::cout << "my_class1: " << std::endl;
my_class1.print();
}
EDIT2: I know about smart pointers. I am specifically interested what happens if I use raw pointers.
You need to implement the copy constructor, copy assignment and destructor.
Additionally, consider changing your vector declaration from
std::vector<MyStruct*> my_vector;
to
std::vector<std::unique_ptr<MyStruct>> my_vector;
so that it actually owns the heap allocated objects properly. Doing this change will help you not write a destructor.
No, std::vector doesn't take care of deep copying of your objects stored by pointer. You have few possibilities to solve this:
Store MyStruct by value.
Store std::unique_ptr<MyStruct>.
Store std::shared_ptr<MyStruct>.
Note that because MyStruct contains only fields of the primitive types, neither of copy constructor, assignment operator and destructor are needed, otherwise you'd have to implement them, default implementation which compiler will generate automatically will be good enough.
I'm trying to supply a parameter pack to initialize an array. I think it should work because:
I'm using sizeof... to get the size of the parameter pack
It's a template, and sizeof is a compile-time construct, so it should be known at compile-time, which means arr should not be a variable length array
I'm forwarding the arguments correctly
Yet I get garbage as output and a warning. First the code:
#include <iostream>
#include <utility>
template <typename... Args>
void foo(Args&&... args)
{
int arr[sizeof...(Args)]{std::forward<Args>(args)()...};
for (auto i = 0u; i < sizeof(arr); ++i)
std::cout << arr[i];
}
int a() { return 1; }
int b() { return 2; }
int c() { return 3; }
int main()
{
foo(a, b, c);
}
Then the warning and output:
warning: iteration 3 invokes undefined behavior [-Waggressive-loop-optimizations]
std::cout << arr[i];
~~~~~~~~~~^~~~~~~
note: within this loop
for (auto i = 0u; i < sizeof(arr); ++i)
~~^~~~~~~~~
1230-282327744327670000-133971368332712
Can anyone see my mistake?
template <typename... Args>
void foo(Args&&... args)
{
// edit 1 : define the extent of the array once, reuse.
constexpr std::size_t extent = sizeof...(Args);
// edit 2 : in this case, no need to forward references since
// we're not actually forwarding them anywhere
int arr[extent]{args()...};
// edit 3 : 0 < i < extent of array
for (std::size_t i = 0; i < extent ; ++i)
std::cout << arr[i];
}
As mentioned in the comments by #Casey, sizeof(arr) returns the size of a variable of the type you chose for your array multiplied for the length of the array itself (in your case, 3 * sizeof(int)).
To solve it, you can either iterate over sizeof...(Args) using this:
for (auto i = 0u; i < sizeof...(Args); ++i)
Or print the values while you fill the array, as it follows:
#include <iostream>
#include <utility>
template <typename... Args>
void foo(Args&&... args) {
int arr[sizeof...(Args)] = {
(std::cout << args(), std::forward<Args>(args)())...
};
(void)arr;
}
int a() { return 1; }
int b() { return 2; }
int c() { return 3; }
int main() {
foo(a, b, c);
}
If the sole purpose of the function is to print the values, you can also use this:
int arr[sizeof...(Args)] = { (std::cout << args(), 0)... };
Note that the code above does not consider the case of sizeof...(Args) equal to 0.
It's quite trivial indeed to do that and I'd left it out of the answer.
I have this struct:
struct noduri {
int nod[100];
};
and this function:
int clearMatrix(int var)
{
cout << all[1].nod[30];
}
int main()
{
noduri all[100];
cout << all[1].nod[30];
return 0;
}
and I want the struct to be assigned to all 100 elements of array all[], when I do cout << all[1].nod[30]; everything works fine, no errors, it outputs 0. When I call clearMatrix(1) I get this error : error: request for member nod in all[1], which is of non-class type int, what am I doing wrong ?!
The array variable all is local to the main function, so you cannot reference it in clearMatrix unless you pass a pointer to it into the function:
int clearMatrix(int var, noduri *all)
{
cout<<all[1].nod[30];
}
int main()
{
noduri all[100];
clearMatrix(5, all);
return 0;
}
you are reffering in the function that array which is not in its scope, you need to do it as
int clearMatrix(int var,noduri *all)
{
cout<<all[1].nod[30]; // as here you have the base address of the array of type noduri you can refer it.
}
int main()
{
noduri all[100];
clearMatrix(5, all);
return 0;
}
You are using raw arrays. That's not a good idea. Use std::vector if the size if not known at compile time, consider std::array if it is known at compile time and dynamic resizing would cause measurable performance problems.
One of the problems with raw arrays in C++ is that it's not at all(!) as easy to pass them to a function like, say, an int or a double. std::vector and std::array, in contrast, are as easy to pass to a function like any other normal type.
Here's a complete example:
#include <array>
#include <iostream>
struct noduri {
std::array<int, 100> nod;
};
void clearMatrix(std::array<noduri, 100> const &array) {
std::cout << array[1].nod[30];
}
int main() {
std::array<noduri, 100> all;
std::cout << all[1].nod[30];
}
Note that std::array is only available if your compiler supports C++11. For an older compiler, use boost::array or just do it with a std::vector.
The code you showed will not be compiled and has no any sense. If I have understood correctly you want to assign each element of the array by some value in function clearMatrix. If so then the code will look the following way
#include <iostream>
struct noduri
{
int nod[100];
};
int clearMatrix( noduri *matrix, int size, int var )
{
for ( int i = 0; i < size; i++ )
{
for ( int &n : matrix[i].nod ) n = var;
}
}
int main()
{
const int N = 100;
noduri all[N] = {};
std::cout << all[1].nod[30] << std::endl;
clearMatrix( all, N, 10 );
std::cout << all[1].nod[30] << std::endl;
return 0;
}
I'm new at using vector, I need a method that return the addres of the vector, this is the semplifide code:
class:
#include<vector>
class A
{
private:
std::vector<int> v;
public:
A()
{
for (int i = 0; i < 5; i++)
v[i] = i;
}
std::vector<int> give()
{
return v;
}
~A() {}
};
main:
#include <iostream>
#include "class.cpp"
int main(int argc, char **argv)
{
A a;
int *vptr = NULL;
vptr = &a.give()[0];
std::vector<int> b;
return 0;
}
this code compile but during the execution a segmentation fault is given
This constructor
A(){
for(int i = 0; i < 5; i++)
v[i] = i;
}
is invalid because the vector has no yet elements that you could use the subscript operator. More correctly would be to write
A() : v( 5 ) {
for(int i = 0; i < 5; i++)
v[i] = i;
}
As for your question then std::vector has member function data that returns the address of its internal buffer with elements.
So you could write
int * give(){ return v.data(); }
or
const int * give() const { return v.data(); }
In main you could write
int *vptr = a.give();
You have several big problems here.
First, in the constructor you're trying to access elements of the vector that don't yet exist:
A(){
for(int i = 0; i < 5; i++)
v[i] = i;
}
vector isn't the same as map where if the element you are looking for with operator[] doesn't exist a new one is created. In vector if you use operator[] with an index that doesn't exist you get Undefined Behavior, and a verly likely crash. You should be inserting items here. On way is push_back:
A(){
for (int i = 0; i < 5; ++i)
v.push_back (i);
}
Next, give() returns a vector by-value:
std::vector<int> give(){
return v;
}
Which makes a copy of v and returns that copy. Well that's technically OK, but when you call give() you don't assign the return value to a variable. What ends up happening is the copy of the vector becomes a temporary object. As soon as the so-called "full-expression" where the temporary was created is done, the temporary is destroyed.
That full-expression is this:
vptr = &a.give()[0];
So, vptr was assigned the address of the first element of that temporary vector, but as soon as the end of this expression is reached that vector is destroyed and vptr now points to hyperspace. If you attempt to dereference this wild pointer, you get Undefined Behavior and a very likely segmentation fault.
To fix this, you could let A tell you the address of the first element of the vector:
class A
{
// [...]
public:
void* give() { return v.data(); }
};