Tworzę klasę typu łańcuchowego, na przykład mały przykład poniżej. Wydaje się, że przy łączeniu funkcji składowych wywoływany jest konstruktor kopiowania. Czy istnieje sposób na pozbycie się wywołania konstruktora kopiowania? W moim poniższym przykładzie z zabawkami oczywiste jest, że mam do czynienia tylko z tymczasowymi, dlatego też „powinien” (może nie według standardów, ale logicznie) być elitarny. Drugim najlepszym wyborem, aby skopiować elision, byłoby wywołanie konstruktora ruchu, ale tak nie jest.
class test_class {
private:
int i = 5;
public:
test_class(int i) : i(i) {}
test_class(const test_class& t) {
i = t.i;
std::cout << "Copy constructor"<< std::endl;
}
test_class(test_class&& t) {
i = t.i;
std::cout << "Move constructor"<< std::endl;
}
auto& increment(){
i++;
return *this;
}
};
int main()
{
//test_class a{7};
//does not call copy constructor
auto b = test_class{7};
//calls copy constructor
auto b2 = test_class{7}.increment();
return 0;
}
Edycja: Kilka wyjaśnień. 1. Nie zależy to od poziomu optymalizacji. 2. W moim prawdziwym kodzie mam bardziej złożone obiekty (np. Przydzielone sterty) niż ints
auto b = test_class{7};
nie wywołuje konstruktora kopiowania, ponieważ jest tak naprawdę równoważny,test_class b{7};
a kompilatory są wystarczająco inteligentne, aby rozpoznać ten przypadek i dlatego mogą z łatwością uniknąć kopiowania. Tego samego nie można zrobićb2
.std::cout
) w swoim kreatorze kopiowania? Bez tego kopia powinna zostać zoptymalizowana.Odpowiedzi:
Częściowa odpowiedź (nie konstruuje się
b2
na miejscu, ale przekształca konstrukcję kopiowania w konstrukcję przenoszenia): Możesz przeciążyć funkcjęincrement
elementu członkowskiego w kategorii wartości powiązanej instancji:To powoduje
przenieść-skonstruować,
b2
ponieważtest_class{7}
jest to tymczasowe i wywoływane jest&&
przeciążenietest_class::increment
.Aby uzyskać prawdziwą konstrukcję na miejscu (tj. Nawet konstrukcję bez ruchu), możesz zamienić wszystkie specjalne i niespecjalne funkcje
constexpr
składowe na wersje. Następnie możesz to zrobića ty nie jesteś ani ruchem, ani kopią konstrukcji, za którą trzeba zapłacić. Jest to oczywiście możliwe w przypadku prostego
test_class
, ale nie bardziej ogólnego scenariusza, który nie dopuszczaconstexpr
funkcji składowych.źródło
b2
nie można jej modyfikować.constinit
byłby to sposób, aby tam pójść.this
samo, coconst
funkcje członkówZasadniczo przypisanie odwołania do wartości wymaga wywołania konstruktora, tj. Kopii lub przeniesienia . Różni się to od wymazywania kopii, gdy wiadomo, że po obu stronach funkcji jest ten sam odrębny obiekt. Również odniesienia może odnosić się do obiektu udostępnionego podobnie jak wskaźnik.
Najprostszym sposobem jest prawdopodobnie optymalizacja konstruktora kopiowania. Ustawienie wartości jest już zoptymalizowane przez kompilator, tylko
std::cout
tego nie można zoptymalizować.(lub po prostu usuń konstruktor kopiowania i przenoszenia)
przykład na żywo
Ponieważ problem dotyczy w zasadzie referencji, rozwiązaniem prawdopodobnie nie jest zwracanie referencji do obiektu, jeśli chcesz przerwać kopiowanie w ten sposób.
Trzecia metoda polega przede wszystkim na wymuszeniu kopiowania - wymaga to jednak przepisania lub enkapsulacji operacji w jedną funkcję, a tym samym całkowitego uniknięcia problemu (jestem świadomy, że to może nie być to, czego chcesz, ale może być rozwiązanie dla innych użytkowników):
Czwarta metoda wykorzystuje zamiast tego ruch, albo jawnie wywołany
lub jak widać w tej odpowiedzi .
źródło