Как shared_ptr увеличивает счетчик при передаче по значению?

У меня есть этот пример кода ниже. Я немного знаю о RVO (оптимизация возвращаемого значения) и о том, как конструктор копирования и оператор присваивания пропускаются во время оптимизации, а возвращаемое значение помещается непосредственно в память слева. Итак, если общий указатель работает с RVO, как общий указатель знает, когда увеличить свой счетчик? Потому что по какой-то причине я думал, что класс общих указателей будет знать, когда увеличивать счетчик, на основе количества копий или назначений, которые он сделал.

#include <iostream>
#include <memory>
using namespace std;
class A{
public:
    A(){}
    A(const A& other){ std::cout << " Copy Constructor " << std::endl; }
    A& operator=(const A&other){
        std::cout << "Assingment operator " <<  std::endl;        
        return *this;
    }    
    ~A(){
        std::cout << "~A" <<  std::endl;
    } 
};

std::shared_ptr<A> give_me_A(){
    std::shared_ptr<A> sp(new A);
    return sp;
}

void pass_shared_ptr_by_val(std::shared_ptr<A> sp){

    std::cout << __func__ << ": count  sp = " << sp.use_count() << std::endl;
    std::shared_ptr<A> sp1 = sp;
    std::cout << __func__ << ": count  sp = " << sp.use_count() << std::endl;
    std::cout << __func__ << ": count sp1 = " << sp1.use_count() << std::endl;
}

void pass_shared_ptr_by_ref(std::shared_ptr<A>& sp){
    std::cout << __func__ << ": count  sp = " << sp.use_count() << std::endl;  
    std::shared_ptr<A> sp1 = sp;
    std::cout << __func__ << ": count  sp = " << sp.use_count() << std::endl;
    std::cout << __func__ << ": count sp1 = " << sp1.use_count() << std::endl;
}

int main(){

    {
        shared_ptr<A> sp3 = give_me_A();

        std::cout << "sp3 count = " << sp3.use_count() << std::endl;
        pass_shared_ptr_by_val(sp3);
        pass_shared_ptr_by_ref(sp3);
    }
return 0;
}

выход:

sp3 count = 1


pass_shared_ptr_by_val: count sp = 2

pass_shared_ptr_by_val: count sp = 3

pass_shared_ptr_by_val: count sp1 = 3


pass_shared_ptr_by_ref: счетчик sp = 1

pass_shared_ptr_by_ref: счетчик sp = 2

pass_shared_ptr_by_ref: count sp1 = 2

~A


person solti    schedule 04.07.2016    source источник
comment
Если выполняется RVO, то общий указатель не должен увеличивать счетчик ссылок, потому что копирование не выполняется. Я не уверен, в чем ваш вопрос. Какого результата вы ожидаете?   -  person TartanLlama    schedule 04.07.2016
comment
@TartanLlama Я думал, что RVO также происходит при передаче по значению ... следовательно, конструктор копирования не вызывается ... но я ошибался ... при передаче по значению конструктор копирования вызывается, следовательно, счетчик увеличивается. Я думаю, что мои сомнения теперь ясны   -  person solti    schedule 04.07.2016


Ответы (1)


Если копии нет, то подсчитывать нечего.

Если используется RVO, копии не создаются, так зачем увеличивать счетчик ссылок? Нет никакого дополнительного объекта, который можно было бы уничтожить и уменьшить счетчик ссылок.

person Jesper Juhl    schedule 04.07.2016
comment
так в give_me_A функции RVO не бывает? - person solti; 04.07.2016
comment
@solti Есть (или может). Счетчик ссылок трогать не нужно, потому что копии нет. - person TartanLlama; 04.07.2016
comment
@Jesper Juhl, а как насчет pass_shared_ptr_by_val .. здесь счетчик увеличивается - person solti; 04.07.2016
comment
Если копия сделана, счетчик ссылок увеличится. Если используется RVO, копирование не производится, и счетчик ссылок не увеличивается. Просто как тот. - person Jesper Juhl; 04.07.2016
comment
@JesperJuhl Итак, у меня вопрос о человеке внутри pass_shared_ptr_by_val, счетчик увеличивается ... значит, здесь копия сделана правильно? Но я читал кое-где, где RVO используется также внутри pass by val .. не так ли? - person solti; 04.07.2016
comment
Вы можете прочитать правила о том, когда RVO может произойти здесь: ru .cppreference.com / w / cpp / language / copy_elision Обратите внимание, что компилятор не требуется для выполнения RVO, даже если это возможно (некоторые изменения в C ++ 17). - person Jesper Juhl; 04.07.2016