Référence et déplacement de la valeur C ++

Inférence d'argument de modèle

Lors de la transmission de paramètres réels à un paramètre de fonction avec un type de modèle, les seuls types pouvant être automatiquement convertis sont la conversion const et la conversion de tableau ou de fonction en pointeur (la constante de niveau supérieur est ignorée dans les paramètres formels et les paramètres réels), la conversion arithmétique et la dérivation La conversion de classe en classe de base et la conversion définie par l'utilisateur ne fonctionneront pas.

Type de retour arrière:

template <typename It>
auto func(It beg, It end) -> decltype(*beg){
	return *beg;
}

Un paramètre formel de référence rvalue peut accepter rvalue ou lvalue, ce qui entraîne différentes inférences:

template <typename T>
void f(T &&){
    
}
int i = 0;
f(i);    //如果实参是左值,则T被推导为左值引用(int&), 形参(T& &&)也折叠为左值引用(int&)
f(0);    //如果实参是右值,则T被推导为(int),形参是右值引用(int &&)

La réalisation de move: En fait, il s'agit de convertir la lvalue en référence rvalue, et rien d'autre n'est fait.

template <typename T>
typename remove_reference<T>::type&& move(T&& t){
    return static_cast<typename remove_reference<T>::type&&>(t);
}

std::forward<T>()Transfert parfait: renvoyer la référence de valeur de T (un pliage peut se produire, renvoyer la référence de valeur)

template<typename F, typename T1, typename T2>
void flip(F f, T1 &&t1, T2 &&t2){
	f(std::forward<T2>(t2), std::forward<T1>(t1));  //完美保持t1和t2的属性
}

Si l'argument est une valeur r, alors T est un type commun, forward renverra une référence rvalue (T &&)

Si le paramètre fruit est une lvalue, T est un type de référence lvalue, forward renvoie la référence rvalue de la référence lvalue (repliée en une référence lvalue)

Règles de pliage :

  • X& &, X& &&, X&& &Sont pliées en une valeur de référence gauche
  • X&& &&Réduire à la référence rvalue

À propos des références rvalue et déplacer: https://www.zhihu.com/question/50652989

string s1 = "move";
string p = std::move(s1); //触发string的移动构造函数,s1置为空
string s2 = "not";
string&& p2 = std::move(s2); //p2只是s2的右值引用,没有除法移动构造函数,s2非空

Surcharger, couvrir, cacher


Processus d'analyse de l'appel de fonction en C ++ :p.func();

  • Déterminez d'abord le type statique de p
  • Recherchez dans la classe correspondant au type statique de p func. Si vous ne le trouvez pas, continuez à rechercher le long de la chaîne d'héritage vers le haut. Sinon, signalez une erreur.
  • Après l'avoir trouvé func, vérifiez le type de paramètre
  • Si l'appel est légal
    • S'il funcs'agit d'une fonction virtuelle et que p est une référence ou un pointeur, il décidera quelle version de la fonction virtuelle exécuter à l'exécution
    • Sinon, le compilateur générera un appel de fonction (le compilateur décide lequel appeler)

La recherche de nom est prioritaire sur la vérification de type. Si une fonction portant le même nom mais des paramètres différents de la classe de base est trouvée dans la classe dérivée, la fonction de classe de base sera toujours masquée (sans surcharge) et la correspondance de type ne sera pas recherchée dans la classe de base Appel de fonction.


Référence: https://www.cnblogs.com/txwsh1/archive/2008/06/28/1231751.html

Les caractéristiques des fonctions membres surchargées
(1) La même portée (dans la même classe);
(2) Le nom de la fonction est le même;
(3) Les paramètres sont différents;
(4) Le mot-clé virtuel est facultatif.
Le remplacement consiste à affecter une fonction de classe dérivée pour remplacer une fonction de classe de base, caractérisée par
(1) différentes étendues (situées respectivement dans la classe dérivée et la classe de base);
(2) le même nom de fonction;
(3) les mêmes paramètres;
(4) la fonction de classe de base doit avoir mot-clé virtuel.
"Masqué" signifie que la fonction de la classe affectée protège la fonction de classe de base du même nom. Les règles sont les suivantes
(1) Si la fonction de la classe dérivée porte le même nom que la fonction de la classe de base, mais les paramètres sont différents. À ce stade, quelle que soit la présence ou l'absence du mot-clé virtuel, les fonctions de la classe de base seront masquées (à ne pas confondre avec la surcharge).
(2) Si la fonction de la classe dérivée a le même nom que la fonction de la classe de base et que les paramètres sont les mêmes, mais la fonction de classe de base n'a pas le mot-clé virtuel. Pour le moment, les fonctions de la classe de base sont cachées (à ne pas confondre avec la couverture)

class Base{
public:
	virtual int fcn();    
};
class D1: public Base{
    int fcn(int); //隐藏基类的fcn,不是虚函数;同时继承了Base::fcn();
    virtual void f2(); //新的虚函数
};
class D2: public D1{
    int fcn(int); //非虚函数,隐藏了D1::fcn(int);
    int fcn(); //覆盖了Base::fcn();
    void f2(); //覆盖了D1::f2();
}

Conversion de type

dynamic_cast: Si la conversion des informations d'exécution (RTTI) est cohérente avant et après la conversion, elle peut être convertie, sinon définissez nullptr (comme sous-classe sur superclasse)

static_cast: Comme avec le langage c, il n'y a pas de vérification d'exécution et la constante sous-jacente ne peut pas être supprimée (erreur signalée)

reinterpret_cast: Fournit une réinterprétation de niveau inférieur du modèle de l'objet opération

const_cast: Peut être utilisé pour supprimer const et volatile


Copie du timing d'appel du constructeur:

  • Signe égal
  • Paramètre non référencé
  • Fonction retour objet non-référence
  • Structure d'initialisation de la liste

Si le constructeur est explicite, vous devez appeler le constructeur explicitement (vous ne pouvez pas compter sur le constructeur de copie)

Le compilateur peut modifier l'initialisation de la copie en initialisation directe.

L'opérateur d'affectation de copie est appelé pendant l'affectation


Copie de bloc

NoCopy() == default; //合成构造函数

Nocopy(const NoCopy&) = delete;  //阻止拷贝

NoCopy &Nocopy(const NoCopy&) = delete;  //阻止赋值NoCopy() = default; //合成析构函数

Ne retournez pas de référence ou de pointeur sur la pile

Ne renvoyez pas de références sur le tas (il est facile de provoquer des fuites de mémoire), comme l'exemple suivant

derived& func(){
    derived *d = new derived;
    cout<<"func_d:"<<d<<endl;
    return *d;
}

int main(){
    //正确的释放内存
    auto todo = &func();  //
    cout<< todo <<endl;
    delete todo;
    //错误的
    auto d = func();  //此时调用了拷贝构造函数,这时已经无法(合理的)得到func()函数中分配内存的指针了,无法释放内存
}

Vous pouvez utiliser valgrind pour détecter les fuites de mémoire:

valgrind --tool=memcheck --leak-check=full  ./main_c

c ++ renvoie des variables locales: http://www.samirchen.com/function-returns/

Référence Rvalue: https://www.cnblogs.com/tingshuo/archive/2013/01/22/2871328.html

Conversion de type: https://blog.csdn.net/ydar95/article/details/69822540

Désactivez l'optimisation RVO, vous pouvez ajouter des options à g ++ -fno-elide-constructors, sinon le compilateur optimisera la valeur de retour de la fonction et ne créera plus d'objets temporaires (n'appelera plus le constructeur de copie)

Vous pouvez utiliser final et override pour limiter ou forcer la couverture pour éviter les erreurs.

Les fonctions virtuelles de la classe dérivée utiliseront les arguments par défaut de la fonction virtuelle de la classe de base. Par conséquent, il est préférable de conserver les paramètres réels par défaut lors de l'écriture du programme.

La définition d'une fonction virtuelle pure doit être en dehors du corps de classe.

À propos externet static:

  • Déclarez extern dans le fichier d'en-tête et définissez-le une fois dans un fichier source.
  • Définissez statique dans le fichier source. Si elle est définie dans le fichier d'en-tête, chaque introduction du fichier d'en-tête produira une nouvelle définition (pas le même objet).

Concernant les pointeurs et les références: le
compilateur attribue des adresses aux références, mais il est caché aux utilisateurs.
https://stackoverflow.com/questions/57483/what-are-the-differences-between-a-pointer-variable-and-a-reference-variable-in

int x = 0;
int &r = x;
int *p = &x;
int *p2 = &r;
ssert(p == p2);
A publié 74 articles originaux · J'aime 11 · Visites 30 000+

Je suppose que tu aimes

Origine blog.csdn.net/yijiull/article/details/89395424
conseillé
Classement