C++ Tips

1. C++智能指针中引用计数的实现为什么不用static int count这种形式?

答:C++ 中shared_ptr是一个模板类,其 引用计数使用的是私有的指针 int* count,所有实例通过共同的指针来对 引用计数count实现增减。

之所以没有使用 static int count这种形式,是因为 静态成员变量为所有类实例共享,这在有些情况下会导致引用计数发生错误,比如:

SmartPointer<int> a;
// ...
SmartPointer<int> b;
SmartPointer<int> c = b;   // ref count increased due to copying.

当执行完SmartPointer<int> c = b;时, b的引用计数+1,变为2。 但由于count是static的,在所有SmartPointer<int>的实例之间共享,所以 对象a的引用计数也会变为2。

这显然与我们的期望不符。所以,不能使用static形式的引用计数。

2. C++中拷贝构造函数中的参数一定要是引用形式的吗?如果是,原因是什么?

答:拷贝构造函数中的参数一定要是引用形式的。

拷贝构造函数形式如下:

class A
{
public:
    A(int num):num_(num){ }
    A(const A& A_Ins);
private:
    int num_;
};

拷贝构造函数必须以引用的方式传递参数。这是因为,在值传递的方式传递给一个函数的时候,会调用拷贝构造函数生成函数的实参。如果拷贝构造函数的参数仍然是以值的方式,就会无限循环的调用下去,直到函数的栈溢出。

调用拷贝构造函数主要有以下场景:

  • 对象作为函数的参数,以值传递的方式传给函数。 
  • 对象作为函数的返回值,以值的方式从函数返回
  • 使用一个对象给另一个对象初始化

3.拷贝构造函数和赋值运算符

class A
{
public:
  A(int num):num_:num { }
  A(A& aIns); // 拷贝构造函数
  A& operator=(const A& aIns); // 赋值运算符
  
  int num_;
};

拷贝构造函数必须以引用的方式传递参数。这是因为,在值传递的方式传递给一个函数的时候,会调用拷贝构造函数生成函数的实参。如果拷贝构造函数的参数仍然是以值的方式,就会无限循环的调用下去,直到函数的栈溢出。

Q:对于一个类实例,调用 operato = 一定是调用其 赋值运算符吗?

A:不一定。有可能是在调用拷贝构造函数。区分到底是调用拷贝构造函数还是赋值运算符重载,要看有没有生成新的实例;有生成新的实例,是在调用拷贝构造函数,否则是在调用复制运算符。

A ins1(999); // 
A ins2 = ins1; // 生成了新的实例ins2,所以是调用拷贝构造函数。
A ins3(9988);
ins2 = ins3; // 没有生成新的实例,所以是调用 赋值运算符重载。

3.移动构造函数和移动赋值运算符

移动构造函数类似于拷贝构造函数,不同的是移动构造函数的第一个参数是一个右值引用(&&)。

如果一个类的成员都是基本数据类型或者不含有指向堆上分配的内存的指针,那么移动构造与拷贝构造性能无差异。

如果类里有其它资源:例如 动态分配的内存、指向其他数据的指针等,拷贝构造函数中需要以深拷贝(而非浅拷贝)的方式复制对象的所有数据。而移动构造函数仅仅移动数据成员(把原对象里指针成员的指向地址拿过来),不会分配新的内存,所以比拷贝构造函数性能更好。

与处理拷贝构造函数和拷贝赋值运算符一样,编译器也会合成移动构造函数和移动赋值运算符,如果一个类定义了自己的拷贝构造函数,拷贝赋值运算符或析构函数,编译器就不会为它合成移动构造函数和移动赋值运算符。

当一个类没有定义任何自己版本的拷贝构造函数,拷贝赋值运算符,析构函数,且类的每个非静态数据成员都可以移动时,编译器才会为它合成移动构造函数或移动赋值运算符。

class Person
{
public:
    const char*  name_;
    Person(const char* name):name_(name) {};

    Person(const Person& person)
    {
        name_ = person.name_;
        std::cout << "拷贝构造函数" << std::endl;
    }

    Person(const Person&& person)
    {
        name_ = person.name_;
        std::cout << "移动构造函数"<< std::endl;
    }

    Person& operator=(const Person& person)
    {

        name_ = person.name_;
        std::cout << "拷贝赋值运算符" << std::endl;
        return *this;
    }


    Person& operator=(Person&& person)
    {
        if (this != &person) {
            name_ = person.name_;
            std::cout << "移动赋值运算符" << std::endl;
        }
        return *this;
    }
};
 

 
Person getPerson()
{
    Person person("person in func");
    return person;
}

int main(int argc, char* argv[])
{
    Person person1("xiaohong");
    Person person2("xiaoming");
    Person person3(getPerson());//移动构造函数
    Person person4(std::move(person1));//移动构造函数
    Person person5(person2);//拷贝构造函数

    Person person6("xiaolan");
    person6 = std::move(person3);//移动赋值运算
    Person person7("xiaoqi");
    person7 = Person("xiaoqi");//移动赋值运算
    Person person8("xiaoba");
    person8 = person1;//拷贝赋值运算符
    system("pause");
    return 0;
}

Person p1;

std::move(p1) 会把一个左值p1 强制转换为 右值,这样使用p1对其他对象进行赋值或者构造的时候,就可以使用移动赋值/移动构造,提高效率。 可以把move() 理解为 cast_to_right_value()

需要注意的是:从逻辑上来讲,被 std::move()的对象,不应该再继续被使用。

参考:C++移动构造函数和移动赋值运算符 - 简书

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
For the last 10 or so years, I’ve been programming in C++. I really enjoy the language for its power, brevity, and accommodation of three major programming styles—structured programming, object-oriented programming, and generic programming. In addition, C++ has a powerful and concise library that comes with every compiler that conforms to the language standard. Unfortunately, the library is not the easiest thing in the world to learn and use. And, although there are many good C++ textbooks and some very good C++ Standard Library reference books (my copy of Nicolai Josuttis’s excellent The C++ Standard Library is falling apart from use), I haven’t found any works that provide quick, concise, Standard Library solutions to practical programming problems. So, necessity being the mother of invention, I wrote this book to fill that gap. The book’s primary audience is new and intermediate C++ Standard Library programmers. They can be in any application area that uses C++, such as graphics programming, multimedia development, scientific computation, or financial software. They often have titles like Programmer, Software Engineer, Software Developer, or Applications Developer. People in this target audience should have a moderate amount of experience programming C++. This might include a course in the language, studying any of the plethora of C++ textbooks or tutorials, and perhaps even a year or two of actual programming experience. These programmers should also have some experience, even if it is minimal, using the Standard Library. For example, they should be able to call the Standard Library functions and understand the rudiments of templates and Standard Library containers. However, they do not need to know what parts of the Standard Library they should use to solve their programming problems. After all, that’s the point of this book! The book is organized in a way that lets you quickly find the answer to your programming problem. The heart of the book is the 100 tips on using the C++ Standard Library. They’re all short—about two to four pages each. Just look at the tip titles in the table of contents and flip to one you’re interested in. You’ll notice that each tip starts with a short solution. This is a very concise answer to the programming problem. If you’re an experienced Standard Library user or you just need to jog your memory, this short paragraph or two will satisfy you. Following the bare-bones answer is a detailed solution. This is useful if you’ve never used the tip’s technique or if the short solution is just too concise. The detailed answer has a complete C++ program that illustrates the method in the tip. The text discusses the code and gives a thorough explanation of its key points. A few of the programs may seem longer than what is necessary solely to demonstrate a technique. I’ve done this on purpose, though. One of the things that bothers me about many technical books is that the examples are too simplistic to be of much help. Because object-oriented programming is so important to C++, quite a few of the programs use classes, and this causes the code to be longer. However, I find this makes the examples more realistic, helpful, and valuable. Deciding between brevity and practicality is subjective, however, and someone is certainly bound to be disappointed by my choice. Nonetheless, you don’t have to worry about having to slog through endless pages of pontification—the programs are only about a page or two long, and the explanations just slightly longer. You can quickly get a good understanding of your problem’s solution and then get back to the fun stuff—writing code. If you’d like to explore a tip in more detail, you have several options. First, each tip has references to other relevant tips. These tips may contain alternate techniques, related methods, or supplementary material. Second, the tips are grouped according to topic. Thus, for example, if you’re about to start working with vectors and would like some background first, you can leaf through Chapter 4, “Tips on Vectors.” It will give you some tips on the power and pitfalls of this container. Third, Chapter 13 has an application that uses some of the tips in a realistic setting. If the technique you’re interested in is in this chapter, you get to see it in action. Finally, Chapters 1 and 2 contain an overview and review of the Standard Library and its main component, the Standard Template Library. This information helps you see how the tip fits into the general scheme of things and serves as a good review of some basic Standard Library concepts.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值