1

I have class "Obraz", inside her exist vector which need to collect object another class. My problem is when i add a "Trojkat" object it calls the constructor twice. From what I understand this is because vector adds copies of the argument. Is there any way how can I fix this? Because I only need one constructor call.

Fragment of Main:

Obraz o;
cin >> menu;
switch (menu){
case 1: 
    Trojkat t1;
    o.dodajTrojkat(t1);
    break;

Fragment class Obraz:

class Obraz {
private:
    vector <Trojkat> listaT;
public:
    void dodajTrojkat(Trojkat& t) {
        listaT.push_back(t);
    }
};

//EDIT: I have a problem with my copy constructor. Because when I add for example a second object. Without parmeter the constructor is called twice. And when I add the third object, the constructor is called three times.

Fragment Main:

cin >> menu;
switch (menu){
case 1: 
    o.dodajTrojkat();
    break;

Fragment class Obraz:

class Obraz {
private:
    vector <Trojkat> listaT;

public:
    void dodajTrojkat() {
        listaT.emplace_back(); 
    }
};

And other class:

class Punkt {
private:
    int x, y;
public:
    Punkt(){
        cout << "Write x:";
        cin >> x;
        cout << "Write y:";
        cin >> y;
    }
    Punkt(int _x, int _y){
        x = _x;
        y = _y;
    }
    Punkt(const Punkt &p){
        x = p.x;
        y = p.y;
    }
};


class Linia {
private:
    Punkt p1, p2;
public:
    Linia(Punkt &_p1, Punkt &_p2) {
        p1 = _p1;
        p2 = _p2;
    }
    Linia(const Linia &l) {
        p1 = l.p1;
        p2 = l.p2;
    }
};


class Trojkat {
private:
    Linia l1, l2, l3;
public:
    Trojkat(Linia& _l1, Linia& _l2, Linia& _l3) {
        l1 = _l1;
        l2 = _l2;
        l3 = _l3;
    }
    Trojkat(const Trojkat& t) {
        l1 = t.l1;
        l2 = t.l2;
        l3 = t.l3;
    }
};
  • If `dodajTrójkąt` has to accept `Trojkąt` as parameter, than you cannot avoid two constructor calls. You can only choose between copy constructor and move contructor (depending on `Trójkąt` definition). If you can modify `dodajTrójkąt` to accept arguments to create a `Trójkąt`, you could use [`emplace_back`](https://stackoverflow.com/questions/4303513/push-back-vs-emplace-back) and construct `Trójkąt` in place in the vector, only 1 constructor call. – Yksisarvinen Apr 11 '22 at 13:50
  • 2
    Why does the caller create the object? Why does not `dodajTrojkat` create it? If the constructor has no arguments you can simply resize the vector to add elements. – 463035818_is_not_an_ai Apr 11 '22 at 13:50
  • 1
    How is `t1` constructed? You could forward the arguments through `dodajTrojkat` and use `std::vector::emplace_back` – Quimby Apr 11 '22 at 13:50
  • Look into movement semantics (`std::move` and `&&`). Something like this: `void dodajTrojkat(Trojkat&& t) { istaT.push_back(std::move(t)); }` – Aedoro Apr 11 '22 at 13:54
  • I think I'm still doing something wrong. I edited my post, can you take a look? – SzczeryJerry Apr 11 '22 at 15:24

1 Answers1

5

Standard containers own their elements. That implies: An object not in the container is never the same object as an object in the container. Hence, you cannot take an object and insert it into the vector without creating the element in the vector. You can only move or copy the element.

When the elements can be default constructed you can use resize to add elements. On the other hand emplace_back can forward parameters to the constructor to construct the element in place. For example, suppose the elements do not have a default constructor:

struct foo {
    foo(int x) {}
};

Then you can emplace an element like this:

void dodajTrojkat(int x) {
        listaT.emplace_back(x);
}

This will call the constructor only once.


I have a problem with my copy constructor. Because when I add for example a second object. Without parmeter the constructor is called twice. And when I add the third object, the constructor is called three times.

This is most likely because std::vector has to reallocate to make space for more elements. Typically a vector starts out with 0 capacity and while adding elements the capacity increases when needed by a constant factor (often 2 or 3). If you want to avoid reallocations you can call reserve(number_of_to_be_expected_element) before adding elements:

class Obraz {
private:
    vector <Trojkat> listaT;       
public:
    Obraz() {
        listaT.reserve(100);
    }
    void dodajTrojkat() {
        listaT.emplace_back(); 
    }
};
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185