memmove(),memcopy(),memset()对std::string的影响,以及它们在c/c++中正确的使用方法。

memmove(),memcopy(),memset()是c语言中非常常用的函数,具体功能这里不详细介绍。当它们对于c++标准库中的string进行操作时会产生什么影响呢?我们先来看一段程序。

//
//  main.cpp
//  Demo
//
//  Created by 杜国超 on 16/12/1.
//  Copyright © 2016年 杜国超. All rights reserved.
//

#include 
#include 
#include 

class DGucoClass
{
public:
    DGucoClass(){};
    ~DGucoClass()
    {
        std::cout << "~DGucoClass: " << key << std::endl;
    }
    void init(const std::string& namestr,int iage)
    {
        key = namestr;
        age = iage;
    }
    
public:
    std::string key;
    int         age;
};

int main(int argc, const char * argv[]) {
    //初始化四个DGucoClass对象
    std::array dgucoarray;
    DGucoClass dguco1;
    dguco1.init("dguco1dguco1dguco1dguco1dguco1dguco1dguco1dguco1",21);
    DGucoClass dguco2;
    dguco2.init("dguco2dguco2dguco2dguco2dguco2dguco2dguco2dguco2",22);
    DGucoClass dguco3;
    dguco3.init("dguco3dguco3dguco3dguco3dguco3dguco3dguco3dguco3",23);
    DGucoClass dguco4;
    dguco4.init("dguco4dguco4dguco4dguco4dguco4dguco4dguco4dguco4",24);
    
    dgucoarray[0] = dguco1;
    dgucoarray[1] = dguco2;
    dgucoarray[2] = dguco3;
    dgucoarray[3] = dguco4;
    
    for (size_t i = 0; i < dgucoarray.size(); ++i)
    {
        std::cout << "dgucoarray[" << i << "]:" << "key=" << dgucoarray[i].key << " age=" << dgucoarray[i].age;
        std::cout << std::endl;
    }
    std::cout << "***************************************************************************" << std::endl;
    
    //把数组后三个元素向前移动一个位置
    memmove(&dgucoarray, &dgucoarray[1], sizeof(DGucoClass));
    for (size_t i = 0; i < dgucoarray.size(); ++i)
    {
        std::cout << "dgucoarray[" << i << "]:" << "key=" << dgucoarray[i].key << " age=" << dgucoarray[i].age;
        std::cout << std::endl;
    }
    std::cout << "***************************************************************************" << std::endl;
    
    //改变第一个元素的key
    dgucoarray[0].key = "YukiYukiYukiYukiYukiYukiYukiYukiYukiYukiYukiYuki";

    for (size_t i = 0; i < dgucoarray.size(); ++i)
    {
        std::cout << "dgucoarray[" << i << "]:" << "key=" << dgucoarray[i].key << " age=" << dgucoarray[i].age;
        std::cout << std::endl;
    }
    std::cout << "***************************************************************************" << std::endl;
    return 0;
}

memmove(),memcopy(),memset()对std::string的影响,以及它们在c/c++中正确的使用方法。_第1张图片

执行结果可以分为三个部分执行memmove前,执行后,以及改变数组第一个元素后(以*线隔开),我们可以看到执行memmove后跟我预期的一样,数组第一个元素变成和执行memmove前的第二个元素元素一样。但是把第一个元素说改变之后,奇怪的现象发生了,数组第二个元素也跟着变了。为什么呢?(这里推荐一篇文章:http://blog.csdn.net/passion_wu128/article/details/38353959),这和c++ string的内部实现原理有关,详细内容看此处的文章介绍,不再叙述。因为c++string 内部有一个缓冲区和指针,指针指向字符串的内存空间,当我们进行memmove操作时,它只对指针本身进行了copy也就是我们常说的浅copy,copy之后数组前两个元素的string指针指向了同一块内存区,因此我们改变其中一个,另外一个也跟着改变了。除此之外还有一个更严重的问题,我们看到程序在调用最后一个析构函数时挂掉了,这是我们最不愿意看到的。因为两个指针指向了同一块内存,在析构函数中释放了两次,因此在第二次调用析构函数释放了一块已经被释放的内存区,因此久挂了。

在文章中我们可以看到,c++ string其实是有一个缓冲区的,当字符串的长度没有超过缓冲区的长度时,是不会进行额外的内存空间的申请的,也就是说string具体内容,不是由string 内部的指针来决定的。为了验证我们把key的长度变短一点来看看会有什么结果。代码不再展示:,直接看结果

memmove(),memcopy(),memset()对std::string的影响,以及它们在c/c++中正确的使用方法。_第2张图片

  我们可以看到程序的每一部都跟预期的一样,memmove之后并没有因为一个的改变影响另外一个元素,这是为什呢。原因就在于我们字符串的长度没有超过缓冲区的长度,string并没有申请额外的地址空间,字符串保存在自己本身的缓冲区内,当我们进行memmove时把缓冲区也copy过去了,两个元素之间没有任何关联。

我们可以明显的意识到,当我们使用这些内存操作函数时,一定要注意指针的存在,当我们的struct或者class中有指针时一定要小心,不能使用这些函数去操作,我们通过这些函数只能操作指针本身,而指针指向的内存空间我们并没有去管理,因此就会造成各种bug,比如上面的崩溃,和数据错误,当我们使用memset还会导致内存泄漏(销毁指针前,内存空间没有释放)。

你可能感兴趣的:(c++学习)