网易互娱 C++开发实习 一面(暑期)

1. 内存对齐怎么理解?下面两个结构体的大小是多少?

答案:内存对齐主要是为了让 CPU 更高效地访问数据。结构体成员不是简单地按字段大小相加,而是会按照成员自身对齐要求和结构体整体对齐要求插入 padding。

struct S1 {
    char c;
    double b;
    int i;
};

struct S2 {
    S1 s;
    float f;
};

在常见 64 位环境下,double 按 8 字节对齐,int 按 4 字节对齐,char 按 1 字节对齐。S1 的布局一般是:

  • char c 占 1 字节
  • 为了让 double b 按 8 字节对齐,中间补 7 字节
  • double b 占 8 字节
  • int i 占 4 字节
  • 结构体整体要按最大对齐值 8 对齐,末尾再补 4 字节

所以 sizeof(S1) 通常是 24。S2S1 占 24 字节,float f 占 4 字节,结构体整体仍然要按 8 字节对齐,所以末尾补 4 字节,sizeof(S2) 通常是 32。

代码:

#include <iostream>
using namespace std;

struct S1 {
    char c;
    double b;
    int i;
};

struct S2 {
    S1 s;
    float f;
};

int main() {
    cout << sizeof(S1) << endl;
    cout << sizeof(S2) << endl;
    return 0;
}

2. 如何减少结构体 S1 的大小?除了改变变量顺序还有什么办法?

答案:减少结构体大小最直接的办法是调整成员顺序,让大对齐成员放前面,小对齐成员放后面,尽量减少中间 padding。

比如把 double 放前面:

struct S1 {
    double b;
    int i;
    char c;
};

这样常见 64 位环境下大小会从 24 降到 16。除了调整顺序,还可以用 #pragma packalignas 控制对齐,但这类方式要慎重。强行压缩对齐可能会导致非对齐访问,某些平台上性能下降,甚至出现访问异常。如果是网络协议或磁盘文件格式,更推荐明确序列化字段,而不是直接把结构体内存写出去。

代码:

#include <iostream>
using namespace std;

struct S1_old {
    char c;
    double b;
    int i;
};

struct S1_new {
    double b;
    int i;
    char c;
};

int main() {
    cout << sizeof(S1_old) << endl;
    cout << sizeof(S1_new) << endl;
    return 0;
}

3. 左值和右值有什么区别?

答案:左值通常表示有稳定身份、可以取地址的对象,比如变量、数组元素、解引用后的指针。右值通常表示临时值,表达式结束后就会消亡,比如字面量、临时对象、函数返回的非引用对象。简单说,左值更强调“对象在哪里”,右值更强调“这个值是什么”。C++11 引入右值引用之后,右值的价值变得更明显,因为它可以用于移动语义,避免不必要的深拷贝。

代码:

#include <iostream>
using namespace std;

int getValue() {
    return 10;
}

int main() {
    int a = 1;      // a 是左值
    int b = getValue(); // getValue() 返回值是右值

    int* p = &a;    // 可以取地址
    // int* q = &getValue(); // 错误,临时右值不能这样取地址

    cout << *p << " " << b << endl;
}

4. 右值引用的作用是什么?

答案:右值引用主要服务于移动语义和完美转发。没有右值引用时,很多临时对象只能被拷贝;有了右值引用后,可以把临时对象内部资源直接转移给新对象,减少内存分配和数据复制。比如一个对象内部维护堆内存,拷贝时要重新分配并复制内容,而移动时只需要转移指针,再把原对象置为空即可。所以右值引用不是为了让语法更复杂,而是为了解决资源转移效率问题。

代码:

#include <iostream>
using namespace std;

class Buffer {
public:
    Buffer(size_t n) : data_(new int[n]), size_(n) {}

    ~Buffer() {
        delete[] data_;
    }

    Buffer(Buffer&& other) noexcept
        : data_(other.data_), size_(other.size_) {
        other.data_ = nullptr;
        other.size_ = 0;
    }

private:
    int* data_;
    size_t size_;
};

5. std::move 的底层原理是什么?

答案:std::move 本身并不会移动任何东西,它只是一个强制类型转换,把表达式转换成右值引用。真正发生资源转移的是后续调用的移动构造函数或移动赋值函数。所以如果一个类没有实现移动构造,或者移动构造不可用,写了 std::move 也不一定能减少拷贝。另外,被 std::move 之后的对象仍然是有效对象,但它的具体内容通常不应该再依赖,只适合析构、重新赋值或者保持可析构状态。

代码:

#include <iostream>
#include <utility>
using namespace std;

class A {
public:
    A() = default;

    A(const A&) {
        cout << "copy\n";
    }

    A(A&&) noexcept {
        cout << "move\n";
    }
};

int main() {
    A a;
    A b = std::move(a);
    return 0;
}

6. 智能指针是什么?为什么要使用智能指针?

答案:智能指针是用对象来管理指针资源的一种 RAII 封装。它的核心作用是把资源释放放到析构函数里,让对象生命周期结束时自动释放资源,减少内存泄漏、重复释放和异常路径忘记释放的问题。常见智能指针有 unique_ptrshared_ptrweak_ptrunique_ptr 表示独占所有权,shared_ptr 表示共享所有权,weak_ptr 用来观察对象并解决循环引用。

代码:

#include <iostream>
#include <memory>
using namespace std;

struct Node {
    ~Node() {
        cout << "~Node\n";
    }
};

int main() {
    unique_ptr<Node> p1 = make_unique<Node>();

    auto p2 = make_shared<Node>();
    weak_ptr<Node> wp = p2;

    if (auto sp = wp.lock()) {
        cout 

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

C++ 常考面试题总结 文章被收录于专栏

本专栏系统梳理C++方向, 大中厂高频高频面试考点 , 内容皆来自真实面试经历,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力.

全部评论

相关推荐

1.说一下你的断点续传怎么实现的?2.分片出错了怎么办?3.CRC校验和MD5校验有啥区别?性能&nbsp;准确&nbsp;错误率3.如果串改,攻击&nbsp;你怎么解决?4.你的分片&nbsp;怎么保证有序5.&nbsp;你的文件上传&nbsp;如何保证文件上传对了的?6.&nbsp;你说说map&nbsp;和hashmap的区别7.不考虑范围查询的话&nbsp;红黑树和hash表有什么区别8.&nbsp;hash冲突你知道吗?&nbsp;怎么解决?9.&nbsp;你知道的hash算法有哪些?10.hash&nbsp;算出来的是什么&nbsp;是内存地址吗?举个例子1234&nbsp;怎么hash的11.你知道的排序算法有哪些&nbsp;?12.快排实现复杂度是多少&nbsp;&nbsp;最坏&nbsp;最好&nbsp;平均?&nbsp;为什么平均还是nlogn&nbsp;&nbsp;怎么算的13.快速排序&nbsp;的&nbsp;平均时间复杂度的计算方法14.红黑树&nbsp;应用&nbsp;方面&nbsp;介绍一下&nbsp;不考虑区间搜索和Key的有序性,关心&nbsp;KV&nbsp;映射,哈希表和红黑树的适用场景和局限性15.对于字符串而言有什么好的哈希方法16.举个例子对字符串&nbsp;1234&nbsp;的哈希方法,是怎么计算的17.unordered_map&nbsp;重新计算哈希&nbsp;后是怎么映射的&nbsp;rehash&nbsp;怎么操作&nbsp;rehash&nbsp;复杂度会不会很高?18.哈希校验的哈希冲突怎么解决?19.CRC和MD5怎么比较置信度&nbsp;?20.分片顺序&nbsp;分片完整性&nbsp;文件完整性&nbsp;怎么校验21.http3的前向纠错机制22.网络不稳定的情况下,分片怎么做校验是否丢失分片的情况?&nbsp;怎么维持网络稳定性
柠檬微趣一面26人在聊
点赞 评论 收藏
分享
评论
1
4
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务