C++ 11

日常查阅资料所看到的有用的链接:

对于智能指针的使用,实际上是对所有权生命周期的思考,一旦想明白了这两点,那对智能指针的使用也就得心应手了。

 

libzipを試す (圧縮)

https://stackoverflow.com/questions/45131984/customize-stdshared-ptr-deleter

篇一: 用 std::vector 包装 std::string 字符串数组,并将它们转为 const char ** 输出

分别使用了非 vector 方法,vector 方法和带有共享指针的方法,都可以正常使用,不过在使用 std::string.c_str() 给 char * 赋值的时候,并不会创建新的内存,只是返回 std::string 内部的指针,也就是说,std::string 占用的是栈内存,并不需要显式释放

char** arr = new char*[arrayObj];
if (arrayObj) {
  for (size_t i = 0; i < arrayObj; i++) {
    uint32_t size = parameters["url"][i].asString().size() + 1;
    arr[i] = new char[size];
    strcpy_s(arr[i], size,
             parameters["url"][i].asString().c_str());
  }
} 
void old_func(char** carray, size_t size)
{
    for(size_t i = 0; i < size; ++i)
        std::cout << carray[i] << '\n';
}

int main()
{
    std::vector<std::string> strings {"one", "two", "three"};
    std::vector<char*> cstrings;
    cstrings.reserve(strings.size());

    for(size_t i = 0; i < strings.size(); ++i)
        cstrings.push_back(const_cast<char*>(strings[i].c_str()));

    // Do not change any of the strings here as that will
    // invalidate the new data structure that relies on
    // the returned values from `c_str()`
    //
    // This is not an issue after C++11 as long as you don't
    // increase the length of a string (as that may cause reallocation)

    if(!cstrings.empty())
        old_func(&cstrings[0], cstrings.size());
}
 std::vector<std::shared_ptr<std::string>> url_;

for (size_t i = 0; i < arrayObj; i++) {
      url_.push_back(
          std::make_shared<std::string>(parameters["url"][i]
              .asString()));
    }

std::vector<const char*> url_list;
url_list.reserve(url_.size());

for (size_t i = 0; i < url_.size(); ++i)
   url_list.push_back(const_cast<char*>(url_[i].get()->c_str()));

url_list.push_back(NULL);

std::cout << url_list[0] << '\n';
std::cout << url_list[1] << '\n';

 共享指针出了作用域会计数减一,当出现 url_(url) 这样的操作,计数也会加一

一些关于 c_str() 的解释:

std::string 内部的元素,是通过 c_str() 来的,c_str() 并不会再分配内存,仅仅是返回 std::string 的一个内部引用的指针,所以  std::string 出了作用域被释放了, 自然 char* 指向的内存就已经被释放了 ,因为是同一块内存 。

std::string 本质上就是用一个 class 封装了一个 数组 ,c_str() 就是返回的内部数组的首地址。

但是在用 c_str() 返回的指针的时候, 要保证 string 本身不被修改,比如一个 string 内部数组 是 char * internal = "12345";  , c_str() 返回的就是internal 的首地址,首地址被修改,可能是 append了,那么首地址还是有效的,只要 `\0` 存在,那么只是内容变了;  也可能是原来的数组不够长,内部重新分配了内存,那么 首地址就变了,这时候 之前 c_str() 获取到的地址 就无效了。那么去访问这个 无效的 c_str(),就会引发内存异常。 但是内部 重新分配,一定是 先分配内存,再copy内容,再释放之前的内存; 所以内存管理是做好了的。

链接:https://www.cplusplus.com/reference/string/string/c_str/

文档指出:The pointer returned may be invalidated by further calls to other member functions that modify the object.

一个小例子:

std::vector<const char*> url_;

for (size_t i = 0; i < 2; i++) { std::string sss = parameters["url"][i].asString(); url_.push_back(const_cast<char*>(sss.c_str())); }

for 循环两次后会发现 url_  的第一条字符串变成乱码,也就是说 sss.c_str() 首地址由于第二条字符串的加入而变为无效地址。

如果是挨个赋值就不会有这样的问题,

url_.push_back(const_cast<char*>(sss.c_str()));
url_.push_back(const_cast<char*>(www.c_str()));
url_.push_back('\0');
  // std::string 转为 const char** 后,传给接口
  char** url_list = new char*[url_.size() + 1];
  char** temp_ptr = url_list;
  for (size_t i = 0; i < url_.size(); i++) {
    *temp_ptr = new char[url_[i].size() + 1];
    strcpy_s(*temp_ptr++, url_[i].size() + 1, url_[i].c_str());
  } 
  // bvclive_live_set_url_list 是 C 接口,通过 while 遍历数组
  // 故需要额外补充 nullptr
  *temp_ptr = nullptr;

或者

 const char** url_list = new const char*[url_.size() + 1];
  const char** temp_ptr = url_list;
  for (size_t i = 0; i < url_.size(); i++) {
    *temp_ptr++ = url_[i].c_str();
  } 

 智能指针借助 lambda 自动释放

std::shared_ptr<int> p7(new int[10], [](int* p) {delete[]p; });

常用智能指针的使用:

bvclive_engine_ = BvcLiveEngine::New(chained_push_url_, audio_format_);

std::shared_ptr<BvcLiveEngine> BvcLiveEngine::New(std::vector<std::string> url,
                                                  AudioFormat format) {
  auto engine = new BvcLiveEngine(url, format);
  std::shared_ptr<BvcLiveEngine> res(engine);
  if (!res->StartBvclive()) {
    return nullptr;
  }
  return res;
}

静态函数的执行顺序:

  • 静态初始化块的优先级最高,也就是最先执行,并且仅在类第一次被加载时执行;
  • 非静态初始化块和构造函数后执行,并且在每次生成对象时执行一次;
  • 非静态初始化块的代码会在类构造函数之前执行。因此若要使用,应当养成把初始化块写在构造函数之前的习惯,便于调试;
  • 静态初始化块既可以用于初始化静态成员变量,也可以执行初始化代码
  • 非静态初始化块可以针对多个重载构造函数进行代码复用

一文看懂静态初始化块、静态成员、初始化块、构造函数执行顺序以及用途

拷贝构造函数的深浅拷贝:C++拷贝构造函数(深拷贝,浅拷贝)

c++ 四种强制类型转换介绍

c++ 父类指针如何操作子类的新函数:

Base* b =  new  Derived();
b->Func();

// 不安全的转换
Derived* d = (Derived*)b;
d->NewFunc();

---------------------------------------

Base* b =  new  Derived();
b->Func();
// 安全转换
Derived* d =  dynamic_cast <Derived*>(b);
if  (d != NULL)
{
   d->NewFunc();
}

如果要将子类指针指向父类对象,则需要做强制类型转换

之所以使用父类指针指向子类对象(A *p = new B;),目的就是实现多态,通过父类指针可以指向多个不同的子类对象,向不同的对象发送同一个消息,不同的对象在接受时会产生不同的行为。但是根据内存的解释,父类指针无法访问子类的独有的函数,因此这个用法主要是用来实现多态(执行期的动态绑定)

一:虚函数表指针(vptr)创建时机
vptr跟着对象走,所以对象什么时候创建出来,vptr就什么时候创建出来,也就是运行的时候。
当程序在编译期间,编译器会为构造函数中增加为vptr赋值的代码(这是编译器的行为),当程序在运行时,遇到创建对象的代码,执行对象的构造函数,那么这个构造函数里有为这个对象的vptr赋值的语句。

二:虚函数表创建时机

虚函数表创建时机是在编译期间。编译期间编译器就为每个类确定好了对应的虚函数表里的内容。
所以在程序运行时,编译器会把虚函数表的首地址赋值给虚函数表指针,所以,这个虚函数表指针就有值了。

这也是为什么构造函数不能为虚函数。因为在创建对象时会调用构造函数,构造函数在这时初始化对象的虚表指针。如果构造函数是虚函数,那么意味着对象必须要通过虚表指针去调用构造函数,但是在调用构造函数之前,虚表指针还没被赋值,这就出现了矛盾。

另读:C++类内存分布


在 const 成员函数中,既不能改变 this 所指向的对象,也不能改变this所保存的地址,this 的类型是一个指向 const 类型对象的 const 指针。

当 const 在函数名前面的时候修饰的是函数返回值。

当 const 在函数名后面表示是常成员函数,该函数不能修改对象内的任何成员,只能发生读操作,不能发生写操作。 

参考:C++函数前和函数后加const修饰符区别

inline 用法:

(1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。 
(2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构函数可能会隐藏一些行为,如"偷偷地"执行了基类或成员对象的构造函数和析构函数。所以不要随便地将构造函数和析构函数的定义体放在类声明中。一个好的编译器将会根据函数的定义体,自动地取消不值得的内联(这进一步说明了 inline 不应该出现在函数的声明中)。

 内联函数并不是一个增强性能的灵丹妙药。只有当函数非常短小的时候它才能得到我们想要的效果;但是,如果函数并不是很短而且在很多地方都被调用的话,那么将会使得可执行体的体积增大。 
最令人烦恼的还是当编译器拒绝内联的时候。在老的实现中,结果很不尽人意,虽然在新的实现中有很大的改善,但是仍然还是不那么完善的。一些编译器能够足够的聪明来指出哪些函数可以内联哪些不能,但是大多数编译器就不那么聪明了,因此这就需要我们的经验来判断。如果内联函数不能增强性能,就避免使用它!
 
#include<stdio.h>
#ifdef __cplusplus
extern "C"{
#endif

void testCfun();

#ifdef __cplusplus
}
#endif
C++ 支持重载,而 C 不支持,C++ 并不能直接调用C代码写好的接口,因此如果你的C代码想要能够被 C 调用,也想被 C++ 调用,那么别忘了 extern "C"。
 
 
内存泄漏-原因、避免和定位

原文链接: https://www.cnblogs.com/strive-sun/p/15178144.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    C++ 11

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/404605

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月25日 下午4:38
下一篇 2023年4月25日 下午4:38

相关推荐