C++常见笔试面试要点以及常见问题

C++常见笔试面试要点以及常见问题

https://www.cnblogs.com/jiayayao/p/6246468.html

1. C++常见笔试面试要点:

  C++语言相关:

(1) 虚函数(多态)的内部实现(C++虚函数实现多态原理(转载)

(2) 智能指针用过哪些?shared_ptr和unique_ptr用的时候需要注意什么?shared_ptr的实现原理是什么? (智能指针shared_ptr的用法、智能指针unique_ptr的用法)

(3) 特化和泛化(算法的泛化过程(摘自《STL源码剖析》)

(4) 为什么不能在构造函数中调用虚函数?

     当实例化一个派生类对象时,首先进行基类部分的构造,然后再进行派生类部分的构造。当在构造基类部分时,派生类还没被完全创建,从某种意义上讲此时它只是个基类对象。所以在构造函数中调用虚函数,执行的是基类的虚函数,而非派生类的虚函数。

  STL:

(1) vector、list、set、map内部实现以及异同,迭代器插入删除后vector、list、set、map的迭代器是否会失效?

(2) STL除了序列式容器和关联式容器,还有哪些值得学习的?

  TCP/IP:

(1) TCP、UDP异同;

(2) TCP、UDP发送一段字符串,其中的发送过程有什么区别?本人理解:TCP有滑动窗口,流量控制,超时重传等机制。

  数据结构:

(1) 链表的逆置(又称反转);

(2) 链表有无环的检测,两个链表相交有无可能?相交的形态是什么样的?如何确定相交点?

(3) 如何求出数组中最小(或者最大)的k个数(least k问题)?

(4) 如何求出树中两个结点的最低公共祖先?

  本人理解:以上要点必须从根本上明白,理解,不能有糊涂的地方,因为面试官往往会由浅入深的提问,当你不明白一点后,面试官就无需再往下问了,直接确定你的水平了。

智能指针unique_ptr的用法

2016-12-03 17:19 by jiayayao, 2048 阅读, 0 评论, 收藏, 编辑

  unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法:

    std::unique_ptr myPtr(new T);
    std::unique_ptr myOtherPtr = myPtr; // error

  但是unique_ptr允许通过函数返回给其他的unique_ptr,还可以通过std::move来转移到其他的unique_ptr,注意,这时它本身就不再拥有原来指针的所有权了。相比于auto_ptr而言,unique_ptr是显示的转移,而不是莫名其妙的报废,因为auto_ptr调用拷贝构造函数后,原来的对象就失效了。

    std::unique_ptr myPtr(new T);
    std::unique_ptr myOtherPtr = std::move(myPtr); // ok

  对于一般的程序使用std::unique_ptr就够了,如果是多线程方面,可能存在共同使用的问题,可以使用std::shared_ptr,注意不要引起循环引用。

为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer)。

  智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈上的变量自动被销毁,智能指针内部保存的内存也就被释放掉了(除非将智能指针保存起来)。

  C++11提供了三种智能指针:std::shared_ptr, std::unique_ptr, std::weak_ptr,使用时需添加头文件

  shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,删除所指向的堆内存。shared_ptr内部的引用计数是安全的,但是对象的读取需要加锁。

  1. shared_ptr的基本用法
  • 初始化

  可以通过构造函数、std::make_shared辅助函数和reset方法来初始化shared_ptr:

复制代码

#include "stdafx.h"
#include 
#include 
#include 

using namespace std;
class Person
{
public:
    Person(int v) {
        value = v;
        std::cout << "Cons" < p1(new Person(1));// Person(1)的引用计数为1

    std::shared_ptr p2 = std::make_shared(2);

    p1.reset(new Person(3));// 首先生成新对象,然后引用计数减1,引用计数为0,故析构Person(1)
                            // 最后将新对象的指针交给智能指针

    std::shared_ptr p3 = p1;//现在p1和p3同时指向Person(3),Person(3)的引用计数为2

    p1.reset();//Person(3)的引用计数为1
    p3.reset();//Person(3)的引用计数为0,析构Person(3)
    return 0;
}

复制代码

   注意,不能将一个原始指针直接赋值给一个智能指针,如下所示,原因是一个是类,一个是指针。

    std::shared_ptr p4 = new int(1);// error

  reset()包含两个操作。当智能指针中有值的时候,调用reset()会使引用计数减1.当调用reset(new xxx())重新赋值时,智能指针首先是生成新对象,然后将就对象的引用计数减1(当然,如果发现引用计数为0时,则析构旧对象),然后将新对象的指针交给智能指针保管。

  • 获取原始指针  
    std::shared_ptr p4(new int(5));
    int *pInt = p4.get();
  • 指定删除器

  智能指针可以指定删除器,当智能指针的引用计数为0时,自动调用指定的删除器来释放内存。std::shared_ptr可以指定删除器的一个原因是其默认删除器不支持数组对象,这一点需要注意。

  2. 使用shared_ptr需要注意的问题

  但凡一些高级的用法,使用时都有不少陷阱。

  • 不要用一个原始指针初始化多个shared_ptr,原因在于,会造成二次销毁,如下所示:
        int *p5 = new int;
        std::shared_ptr p6(p5);
        std::shared_ptr p7(p5);// logic error
  • 不要在函数实参中创建shared_ptr。因为C++的函数参数的计算顺序在不同的编译器下是不同的。正确的做法是先创建好,然后再传入。
    function(shared_ptr(new int), g());
  • 禁止通过shared_from_this()返回this指针,这样做可能也会造成二次析构。
  • 避免循环引用。智能指针最大的一个陷阱是循环引用,循环引用会导致内存泄漏。解决方法是AStruct或BStruct改为weak_ptr。

复制代码

struct AStruct;
struct BStruct;

struct AStruct {
    std::shared_ptr bPtr;
    ~AStruct() { cout << "AStruct is deleted!"< APtr;
    ~BStruct() { cout << "BStruct is deleted!" << endl; }
};

void TestLoopReference()
{
    std::shared_ptr ap(new AStruct);
    std::shared_ptr bp(new BStruct);
    ap->bPtr = bp;
    bp->APtr = ap;
}

C++11之std::function和std::bind

2016-12-06 21:30 by jiayayao, 20016 阅读, 0 评论, 收藏, 编辑

  std::function是可调用对象的包装器,它最重要的功能是实现延时调用:

复制代码

#include "stdafx.h"
#include// std::cout
#include// std::function

void func(void)
{
    std::cout << __FUNCTION__ << std::endl;
}

class Foo
{
public:
    static int foo_func(int a)
    {
        std::cout << __FUNCTION__ << "(" << a << ") ->: ";
        return a;
    }
};

class Bar
{
public:
    int operator() (int a)
    {
        std::cout << __FUNCTION__ << "(" << a << ") ->: ";
        return a;
    }
};

int main()
{
    // 绑定普通函数
    std::function fr1 = func;
    fr1();

    // 绑定类的静态成员函数
    std::function fr2 = Foo::foo_func;
    std::cout << fr2(100) << std::endl;

    // 绑定仿函数
    Bar bar;
    fr2 = bar;
    std::cout << fr2(200) << std::endl;

    return 0;
}

复制代码

  由上边代码定义std::function fr2,那么fr2就可以代表返回值和参数表相同的一类函数。可以看出fr2保存了指代的函数,可以在之后的程序过程中调用。这种用法在实际编程中是很常见的。

  std::bind用来将可调用对象与其参数一起进行绑定。绑定后可以使用std::function进行保存,并延迟到我们需要的时候调用:

  (1) 将可调用对象与其参数绑定成一个仿函数;

  (2) 可绑定部分参数。

  在绑定部分参数的时候,通过使用std::placeholders来决定空位参数将会是调用发生时的第几个参数。

复制代码

#include "stdafx.h"
#include// std::cout
#include// std::function

class A
{
public:
    int i_ = 0; // C++11允许非静态(non-static)数据成员在其声明处(在其所属类内部)进行初始化

    void output(int x, int y)
    {
        std::cout << x << "" << y << std::endl;
    }

};

int main()
{
    A a;
    // 绑定成员函数,保存为仿函数
    std::function fr = std::bind(&A::output, &a, std::placeholders::_1, std::placeholders::_2);
    // 调用成员函数
    fr(1, 2);

    // 绑定成员变量
    std::function fr2 = std::bind(&A::i_, &a);
    fr2() = 100;// 对成员变量进行赋值
    std::cout << a.i_ << std::endl;


    return 0;
}

boost::condition_variable的使用

2015年03月12日 14:33:59 oiooooio 阅读数:4572 标签: c++ boost 多线程 condition_variable 更多

个人分类: boost C++

这篇文章介绍boost::condition_variable的使用。

主要是在多线程的情况下,一般来说boost::condition_variable是用来进行多线程同步的,下面的代码主要测试了notify_one和notify_all的使用。

调用notify_one的时候,启用一个线程。

调用notify_all的时候,激活所有的线程。

当频繁调用notify_one的时候,并不会一直调用唯一的一个线程(在多个线程的情况下),他会激活其他线程,所以优先使用notify_one。

当数据量小于线程数量的时候,如果调用notify_all则会造成其他线程的空运行。

在结尾,附上测试结果。

 

 

 

 
  1. // ThreadTest.cpp : 定义控制台应用程序的入口点。

  2. //

  3.  
  4. #include "stdafx.h"

  5.  
  6. #include "boost/thread.hpp"

  7. #include "boost/thread/condition_variable.hpp"

  8. #include "boost/thread/mutex.hpp"

  9. #include

  10. #include

  11. #include

  12.  
  13. boost::condition_variable _g_cv;

  14. boost::mutex _g_cv_mutex;

  15. bool _g_is_quit = false;

  16.  
  17.  
  18. void ThreadFunc_1()

  19. {

  20. boost::mutex::scoped_lock lock(_g_cv_mutex);

  21.  
  22. while (!_g_is_quit)

  23. {

  24. _g_cv.wait(lock);

  25. printf("ThreadFunc_1.\n");

  26. // Sleep(10);

  27. }

  28. }

  29.  
  30. void ThreadFunc_2()

  31. {

  32. boost::mutex::scoped_lock lock(_g_cv_mutex);

  33.  
  34. while (!_g_is_quit)

  35. {

  36. _g_cv.wait(lock);

  37. printf("ThreadFunc_2.\n");

  38. // Sleep(10);

  39. }

  40. }

  41.  
  42. void ThreadFunc_3()

  43. {

  44. boost::mutex::scoped_lock lock(_g_cv_mutex);

  45.  
  46. while (!_g_is_quit)

  47. {

  48. _g_cv.wait(lock);

  49. printf("ThreadFunc_3.\n");

  50. // Sleep(10);

  51. }

  52. }

  53.  
  54. void ThreadFunc_4()

  55. {

  56. boost::mutex::scoped_lock lock(_g_cv_mutex);

  57.  
  58. while (!_g_is_quit)

  59. {

  60. _g_cv.wait(lock);

  61. printf("ThreadFunc_4.\n");

  62. // Sleep(10);

  63. }

  64. }

  65.  
  66.  
  67. void ThreadControl()

  68. {

  69. #define THREADCOUNT 4

  70.  
  71. typedef void(*FUNC)();

  72. FUNC threadArray[4] = { ThreadFunc_1, ThreadFunc_2, ThreadFunc_3, ThreadFunc_4 };

  73.  
  74. for (size_t i = 0; i < THREADCOUNT; i++)

  75. {

  76. boost::thread th(threadArray[i]);

  77. }

  78. }

  79.  
  80.  
  81. int _tmain(int argc, _TCHAR* argv[])

  82. {

  83. ThreadControl();

  84.  
  85. using namespace std;

  86. int value = 0;

  87. while (true)

  88. {

  89. printf("enter 1 to notify one thread.\n");

  90. printf("enter 2 to notify thread one by one.\n");

  91. printf("enter 3 to notify all threads.\n");

  92. printf("enter <-1> to quit.\n");

  93.  
  94. cin >> value;

  95. switch (value)

  96. {

  97. case -1:

  98. _g_is_quit = true;

  99. break;

  100. case 1:

  101. _g_cv.notify_one();

  102. break;

  103. case 2:

  104. for (size_t i = 0; i < THREADCOUNT; i++)

  105. {

  106. _g_cv.notify_one();

  107. }

  108. break;

  109. case 3:

  110. _g_cv.notify_all();

  111. break;

  112. default:

  113. printf("enter again.\n");

  114. break;

  115. }

  116.  
  117. if (_g_is_quit){

  118. break;

  119. }

  120. }

  121.  
  122. system("pause");

  123. return 0;

  124. }

 

测试结果:

--------------------------------
enter 1 to notify one thread.
enter 2 to notify thread one by one.
enter 3 to notify all threads.
enter <-1> to quit.
1
ThreadFunc_3.


2
ThreadFunc_2.
ThreadFunc_1.
ThreadFunc_4.
ThreadFunc_3.




4
enter again.


3
ThreadFunc_2.
ThreadFunc_1.
ThreadFunc_3.
ThreadFunc_4.

你可能感兴趣的:(C++)