精华内容
下载资源
问答
  • Vector拷贝构造函数

    千次阅读 2015-09-07 12:50:18
    大家都知道拷贝构造函数调用的常见情形...vector中保存了很多对象的拷贝,当vector调用拷贝构造函数时,容器里面的对象都会被拷贝一份到新的容器里,如果容器中对象数目比较多,则这样的开销是十分昂贵的。但是看到一

    大家都知道拷贝构造函数调用的常见情形包括

    1.函数参数传递,函数实参到形参的过程中调用拷贝构造

    2.函数返回,函数返回一个对象时会调用拷贝构造函数

    3.对象定义时赋值 如 A a=b 这里b也是类A的一个对象


    vector中保存了很多对象的拷贝,当vector调用拷贝构造函数时,容器里面的对象都会被拷贝一份到新的容器里,如果容器中对象数目比较多,则这样的开销是十分昂贵的。但是看到一些工程代码中,函数里面局部vector对象里面保存了大量的对象,在函数结束时直接将vector对象返回。我就在想,这样一来岂不是会有很大的性能开销。经过我自己写的一个demo验证,得出结论:vector其实是存在两个拷贝构造函数的,在VS2012中两个函数的定义如下:

    拷贝构造函数一:

    vector(const _Myt& _Right)
     #if _HAS_CPP0X
    : _Mybase(_Right._Getal().select_on_container_copy_construction())
     #else /* _HAS_CPP0X */
    : _Mybase(_Right._Getal())
     #endif /* _HAS_CPP0X */
    { // construct by copying _Right
    if (_Buy(_Right.size()))
    _TRY_BEGIN
    this->_Mylast = _Ucopy(_Right.begin(), _Right.end(),
    this->_Myfirst);
    _CATCH_ALL
    _Tidy();
    _RERAISE;
    _CATCH_END
    }


    拷贝构造函数二:

    vector(_Myt&& _Right)
    : _Mybase(_Right._Getal())
    { // construct by moving _Right
    _Assign_rv(_STD forward<_Myt>(_Right));
    }


    形如:Vector v1=v2会调用拷贝构造函数一,在该函数中会将v2中的所有元素全部拷贝一份到v1里面,调用拷贝构造函数的开销是相当昂贵的。

    但是当 形如 vector v1=fun();  fun(){ vector v; return v}这样的函数调用,在函数返回时会调用拷贝构造函数二,在拷贝构造函数二中只是会修改 v1的三个迭代器(_Myfirst、 _Mylast、 _Myend)使得V1的三个迭代器指向v中对应迭代器所指向的位置,并且把v的三个迭代器赋值为空,使得在v析构时不会修改v容器中的元素,这样就相当于v1中保存了v中的所有元素,并且没有容器中元素拷贝的性能损失。


    以下是我的Demo:

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


    class Test
    {
    public:
    int data;
    Test()
    {
    cout<<"Test Constrcut"<<endl;
    }
    ~Test()
    {
    cout<<"Test Destruct"<<endl;
    }
    Test(const Test&t)
    {
    this->data=t.data;
    cout<<"Test Copy"<<endl;
    }
    };


    vector<Test> fun()
    {
    vector<Test>can;
    Test t;
    t.data=12;
    can.push_back(t);


    vector<Test>can2=can;//测试第一个拷贝构造函数


    return can;
    }


    int main()
    {
    vector<Test> can=fun();//测试第二个拷贝构造函数
    }


    希望大家指出其中的错误,非常感谢

    展开全文
  • 堆,栈,Vector存储类型,拷贝构造函数等 JeffChen » 堆,栈,Vector存储类型,拷贝构造函数等堆,栈,Vector存储类型,拷贝构造函数等2012年8月7日 jeffchen 发表评论 阅读评论下面四段示例程序可以说明...

    JeffChen » 堆,栈,Vector存储类型,拷贝构造函数等

    堆,栈,Vector存储类型,拷贝构造函数等

    下面四段示例程序可以说明以下概念:栈,堆, vector如何push_back, vector为什么存对象而最好不要存储指针.
    对照这四段程序的输出,应该能清晰的理解以上区别.

    #include "stdafx.h"
    #include<vector>
    #include <iostream>
    posted on 2013-01-24 14:34 lexus 阅读(...) 评论(...) 编辑 收藏

    转载于:https://www.cnblogs.com/lexus/archive/2013/01/24/2874926.html

    展开全文
  • C.43: Ensure that a copyable (value type) class has a default constructorC.43:确保(值类型)可拷贝类有默认构造函数Reason(原因)Many language and library facilities rely on default constructors to ...
    abd623c967b2b1ba72face93dfa8c37f.png

    C.43: Ensure that a copyable (value type) class has a default constructor

    C.43:确保(值类型)可拷贝类有默认构造函数

    Reason(原因)

    Many language and library facilities rely on default constructors to initialize their elements, e.g. T a[10] and std::vector v(10). A default constructor often simplifies the task of defining a suitable moved-from state for a type that is also copyable.

    很多语言和库设施依靠默认构造函数来初始化它们的元素,例如T a[0]和std::vectorv(10)。默认构造函数经常可以简化为可拷贝类定义适当的移出状态的工作。

    Note(注意)

    A value type is a class that is copyable (and usually also comparable). It is closely related to the notion of Regular type from EoP and the Palo Alto TR.

    可拷贝(通常也是可比较)的类称为值类型。它和《编程原本》和《STL概念设计》中提到的正规类型之间的联系非常紧密。

    正规类型:https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#SS-concrete

    编程原本:http://elementsofprogramming.com/

    STL概念设计:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3351.pdf

    Example(示例)

    class Date { // BAD: no default constructorpublic:    Date(int dd, int mm, int yyyy);    // ...};vector vd1(1000);   // default Date needed herevector vd2(1000, Date{Month::October, 7, 1885});   // alternative

    The default constructor is only auto-generated if there is no user-declared constructor, hence it's impossible to initialize the vectorvd1in the example above. The absence of a default value can cause surprises for users and complicate its use, so if one can be reasonably defined, it should be.、

    默认构造函数只有在不存在用户定义构造函数时才会自动生成,因此像上面代码中vector vd1那样的初始化是不可能的。默认值的缺失可能令用户感到意外并且增大使用的难度,因此如果有可能合理地定义它,就那样做。

    Date is chosen to encourage thought: There is no "natural" default date (the big bang is too far back in time to be useful for most people), so this example is non-trivial.{0, 0, 0} is not a valid date in most calendar systems, so choosing that would be introducing something like floating-point's NaN. However, most realistic Date classes have a "first date" (e.g. January 1, 1970 is popular), so making that the default is usually trivial.

    选择日期类是为了推进思考:不存在"自然"的默认日期(对于大多数人来说,以宇宙大爆炸的时刻作为默认值需要将时间回退的太多了,不具备实际意义),因此这个例子不具备一般性。{0,0,0}在大多数日历系统中都不是合法的日期,因此选择它将会引起类似浮点数的NaN问题。

    NaN:不是数字,或者说无效数字。

    class Date {public:    Date(int dd, int mm, int yyyy);    Date() = default; // [See also](#Rc-default)    // ...private:    int dd = 1;    int mm = 1;    int yyyy = 1970;    // ...};vector vd1(1000);

    Note(注意)

    A class with members that all have default constructors implicitly gets a default constructor:

    如果一个类的所有成员都有默认构造函数,那么这个类也隐式得到一个默认构造函数。

    struct X {    string s;    vector v;};X x; // means X{{}, {}}; that is the empty string and the empty vector

    Beware that built-in types are not properly default constructed:

    注意:内置类型没有被正确地默认构造:

    struct X {    string s;    int i;};void f(){    X x;    // x.s is initialized to the empty string; x.i is uninitialized    cout << x.s << ' ' << x.i << '';    ++x.i;}

    Statically allocated objects of built-in types are by default initialized to 0, but local built-in variables are not. Beware that your compiler may default initialize local built-in variables, whereas an optimized build will not. Thus, code like the example above may appear to work, but it relies on undefined behavior. Assuming that you want initialization, an explicit default initialization can help:

    静态分配的内置类型被默认初始化为0,办事局部的内置类型没有。注意你的编译器有可能初始化局部的内置类型变量,尽管优化状态的编译不会。因此上面示例中的代码看起来可以动作,但是者依靠(编译器,译者注)没有定义的行为。如果你需要初始化,明确的默认初始化可以帮忙:

    struct X {    string s;    int i {};   // default initialize (to 0)};

    Notes(注意)

    Classes that don't have a reasonable default construction are usually not copyable either, so they don't fall under this guideline.

    不包含合理的默认构造动作的类通常也不是可拷贝的,因此它们不算对本准则的违反。

    For example, a base class is not a value type (base classes should not be copyable) and so does not necessarily need a default constructor:

    例如,基类不是值类型(基类不应该可拷贝)而且不需要默认构造函数。

    // Shape is an abstract base class, not a copyable value type.// It may or may not need a default constructor.struct Shape {    virtual void draw() = 0;    virtual void rotate(int) = 0;    // =delete copy/move functions    // ...};

    A class that must acquire a caller-provided resource during construction often cannot have a default constructor, but it does not fall under this guideline because such a class is usually not copyable anyway:

    一个类如果必须在构造期间要求调用者提供资源,通常不能拥有默认构造函数,但是它没有违反本准则,因为这样的类通常无论如何也是不能拷贝的。

    // std::lock_guard is not a copyable value type.// It does not have a default constructor.lock_guard g {mx};  // guard the mutex mxlock_guard g2;      // error: guarding nothing

    A class that has a "special state" that must be handled separately from other states by member functions or users causes extra work (and most likely more errors). Such a type can naturally use the special state as a default constructed value, whether or not it is copyable:

    有的类具有某种“特殊状态”,必须通过成员函数或者用户引发(最有可能是错更多的错误)的特别动作彼此分开进行处理。这样的类型可以自然地使用特殊状态作为默认构造的初始值,不管它是否是可拷贝的。

    // std::ofstream is not a copyable value type.// It does happen to have a default constructor// that goes along with a special "not open" state.ofstream out {"Foobar"};// ...out << log(time, transaction);

    Similar special-state types that are copyable, such as copyable smart pointers that have the special state "==nullptr", should use the special state as their default constructed value.

    类似的可拷贝的特殊状态类型,例如包含“==nullprt"这样的特殊状态的可拷贝的智能指针,应该使用特殊状态作为它们默认构造的初始值。

    However, it is preferable to have a default constructor default to a meaningful state such as std::strings "" and std::vectors {}.

    然而,更可取的做法是让默认构造函数默认生成一个有意义的状态,例如std::string的“”和std::vectors{}。

    Enforcement(实施建议)

    • Flag classes that are copyable by = without a default constructor如果类实现了赋值运算符但却没有构造函数,进行提示。
    • Flag classes that are comparable with == but not copyable如果类可以通过比较运算符进行比较但却不是可拷贝的,进行提示。

    原文链接

    https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c43-ensure-that-a-copyable-value-type-class-has-a-default-constructor


    觉得本文有帮助?请分享给更多人。

    更多文章请关注微信公众号【面向对象思考】!

    面向对象开发,面向对象思考!

    展开全文
  • 一、深拷贝和浅拷贝 ...这个默认的拷贝构造函数采用的是“位拷贝”(浅拷贝),而非“值拷贝”(深拷贝)的方式,如果类中含有指针变量,默认的拷贝构造函数必定出错。 浅拷贝:只是对指针的拷贝,拷贝后两个

    一、深拷贝和浅拷贝

    浅拷贝,假如在定义一个类A,然后使用类似A obj;  A obj1(obj);或者A obj1 = obj; 时候,由于没有自定义拷贝构造函数,C++编译器自动会产生一个默认的拷贝构造函数。这个默认的拷贝构造函数采用的是“位拷贝”(浅拷贝),而非“值拷贝”(深拷贝)的方式,如果类中含有指针变量,默认的拷贝构造函数必定出错。

    浅拷贝:只是对指针的拷贝,拷贝后两个指针指向同一个内存空间

    深拷贝:不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。

    举一个例子,当我使用vetcor<T>obj申明一个obj容器之后,obj.push_back(obj1)此时就会调用浅拷贝,但是这样会带来一个严重的问题:当obj1释放掉内部的指针时,obj[0]内部的指针也被释放掉了,这样就会产生野指针。


    二、vector和拷贝构造函数

    vector其中一个特点:内存空间只会增长,不会减小,援引C++ Primer:为了支持快速的随机访问,vector容器的元素以连续方式存放,每一个元素都紧挨着前一个元素存储。设想一下,当vector添加一个元素时,为了满足连续存放这个特性,都需要重新分配空间、拷贝元素、撤销旧空间,这样性能难以接受。因此STL实现者在对vector进行内存分配时,其实际分配的容量要比当前所需的空间多一些。就是说,vector容器预留了一些额外的存储区,用于存放新添加的元素,这样就不必为每个新元素重新分配整个容器的内存空间。

    在调用push_back时,每次执行push_back操作,相当于底层的数组实现要重新分配大小;这种实现体现到vector实现就是每当push_back一个元素,都要重新分配一个大一个元素的存储,然后将原来的元素拷贝到新的存储,之后在拷贝push_back的元素,最后要析构原有的vector并释放原有的内存。例如下面程序:

    #include <iostream>
    #include <cstdlib>
    #include <vector>
    
    using namespace std;
    
    class Point
    {
    public:
            Point()
            {
                cout << "construction" << endl;
            }
            Point(const Point& p)//拷贝构造函数
            {
                cout << "copy construction" << endl;
            }
            ~Point()
            {
                cout << "destruction" << endl;
            }
    };
    
    int main()
    {
        vector<Point> pointVec;
        Point a;
        Point b;
        pointVec.push_back(a);
        pointVec.push_back(b);
    
        cout<<pointVec.size()<<std::endl;
    
        return 0;
    }

    输出结果:


    其中执行

    pointVec.push_back(a);

    此时vector会申请一个内存空间,并调用拷贝构造函数将a放到vector中

    再调用

    pointVec.push_back(b);

    此时内存不够 需要扩大内存,重新分配内存 这时再调用拷贝构造函数将a拷贝到新的内存,再将b拷入新的内存,同时有人调用Point拷贝构造函数,最后释放原来的内存 此时调用Point的析构函数。

    注:当释放vector的时候,用clear只能清空vector的内容,而不释放内存,所以需要使用erase。

    三、消除const修饰对象时带来错误

    当我们使用拷贝构造函数的时候,参数内必须用const修饰,此时如果调用该对象的方法时,就会报出这样的错误:

    对象引用前加const报错:不能将“this”指针从“const a”转换为“a &”

    解决方法看别人的博客发现有三种方法:

    1. 解决方法一:不使用const
    2. 使用const_cast<Class *>(ptr),进行相应的转化
     A * b = const_cast<A*>(obj); //obj代表实际应该使用的对象,此时用一个新对象b来消除const限定
     b->GetIt();//编译就没错了
    
    
    3.将相关的函数转化成相应的const函数
    class A
    {
         int m_It;
    public:
         int GetIt() const;
    }
    int A::GetIt() const//这个地方也要加const
    {
       return m_It;
    }
    附上项目中遇到这个问题,解决之后的主要代码
    Action::Action(const Action &action)        //拷贝构造函数,进行深拷贝
    {
        EffeciencyState* pEffeciencyState = NULL;
        Action* pAction = const_cast<Action*>(&action);  //解决const限定
        for(int i = 0; i < pAction->getEffeciencyStateList().length(); i++)
        {
            if(pAction->getEffeciencyStateList()[i]->getType() == normal)
            {
                pEffeciencyState = new EffeciencyState();
                pEffeciencyState->setEffeciencyStateName(pAction->getEffeciencyStateList()[i]->getEffeciencyStateName());
                pEffeciencyState->setEffeciencyStateTime(pAction->getEffeciencyStateList()[i]->getEffeciencyStateTime());
                pEffeciencyState->setDescription(pAction->getEffeciencyStateList()[i]->getDescription());
            }
            else
            {
                pEffeciencyState = new HttpRequest();
                pEffeciencyState->setEffeciencyStateName(pAction->getEffeciencyStateList()[i]->getEffeciencyStateName());
                pEffeciencyState->setEffeciencyStateTime(pAction->getEffeciencyStateList()[i]->getEffeciencyStateTime());
                pEffeciencyState->setDescription(pAction->getEffeciencyStateList()[i]->getDescription());
                pEffeciencyState->setDuringTime(pAction->getEffeciencyStateList()[i]->getDuringTime());
            }
            m_oEffeciencyStateList.push_back(pEffeciencyState);
        }
        m_sActionName = pAction->getActionName();
        m_bVisitState = pAction->getVisitState();
        m_oBeginTime = pAction->getBeginTime();
        m_oEndTime = pAction->getEndTime();
        m_oStateNumberMap = pAction->getStateNumberMap();
        m_oStepActionList = pAction->getStepActionList();
    }

    c++新手,如果有不对的地方希望能帮忙指正,多谢。




    展开全文
  • "调用拷贝"<<endl;} ~A(){if(x!=NULL){delete x; x=NULL;cout<<"调用析构"<<endl;}} }; void main() { int* integer = new int(); *integer = 1; vector<A> Array; A a; a....
  • 那么对于有n个元素的vector调用push_back,若不涉及扩容,则调用一次拷贝构造函数;若涉及扩容,则调用n次移动构造函数和一次拷贝构造函数。 参考: https://blog.csdn.net/nie_quanxin/article/details/81187468 ....
  • Vector容器互换容器的操作,老师说实际用途,可以巧用互换容器的方式来收缩内存,节省空间。 如下: //创建一个Vector容器V vector<int> v; //尾插法给容器加入十万个元素 for (int i = 0; i < ...
  • 拷贝构造函数

    2012-10-19 13:55:11
    拷贝构造函数: 当用一个vector对象初始化另外一个vector对象的时候,应拷贝所有的向量元素并且保证这一拷贝操作确实被调用了。 某一个类型的对象的初始化是由该类型的构造函数实现的。素以实现拷贝操作,我们需要...
  • 一、vector基本概念功能:vector数据结构和数组非常相似,也称为单端数组vector与普通...释放原空间vector容器的迭代器是支持随机访问的迭代器二、vector构造函数功能描述:创建vector容器函数原型:vectorv;//采...
  • vector构造函数有4种形式: 第1种:默认构造函数,采用模板实现类实现,实例代码如下 vector<int> v1; 执行结果是v1为空容器,没有保存任何元素,但是并不意味着v1没有分配内存 第2种:将已有的数组的区间...
  • 拷贝构造函数的调用

    2019-12-27 13:34:07
    拷贝构造函数什么时候调用? 补充: 当一个函数中形参和返回值都是对象,理论上应该调用两次拷贝构造函数,但是实际上只调用了一次。编译器为了提高效率把这两次合并了。 如: #include<iostream> #include<...
  • 18.2.1 vector构造函数

    2020-07-29 11:18:32
    18.2.1 vector构造函数 ...vector<...vector(v.begin(), v....拷贝构造函数 1、默认构造函数 这里写了一个打印vector元素的函数,当然把这个函数写成模板形式更好。 #include <iostream> #include<v
  • 拷贝构造函数的理解错误

    千次阅读 2014-07-18 14:23:09
    我需要实现它的拷贝构造函数,因为我要把它push_back到vector里面去。我过去的一直做法是在赋值操作符中实现真正的操作,在拷贝构造函数中调用。但是在这里却出现了内存错误。 好歹我还写过几年程序,那我就开始了...
  • STL与拷贝构造函数

    2016-08-25 15:26:00
    所有容器提供的都是“value语意”而非“reference...以vector为例,往Vector中(实际上所有STL容器都是这样)放元素,Vector会调用元素类的拷贝构造函数生成的副本,当Vector走出生存期时(),会自动调用其中每个元素
  • void f(const X& rx, X x) { vector<X> vec; /*vector<int> myVec;... // 新元素还没有构造, // 此时不能用[]访问元素 ... // 用元素的默认构造函数构造了两个新的元素 myVec[100] ...
  • c++,拷贝构造函数

    2013-05-31 14:38:39
    #include using namespace std; class Vector { public: Vector();...//拷贝构造函数 void clone(const Vector& v); ~Vector();//析构函数。 void printV() { cout<<"size="<<size<<" rep"<<end
  • 所有容器提供的都是“value语意”而非“reference语意”。... 侯捷、孟岩译 p144页原文 以vector为例,往Vector中(实际上所有STL容器都是这样)放元素,Vector会调用元素类的拷贝构造函数生成的副本,当Vector走...
  • 转载例子:#include&lt;iostream&gt;#include &...vector&gt;#include &lt;fstream&gt;using namespace std;ofstream out("1.txt");class Rock{ public: R...
  • 在查bug中,发现一个参数在构造函数中初始化了,但在拷贝构造函数中未赋值,结果在vector::resize中调用了拷贝构造函数,参数未初始化,导致在release 和 debug版本中结果不一样的问题。 写个dome说明下: ...
  • 在未指定vector大小的时候,第一次push_back操作会调用一次元素的拷贝构造函数(此时vectord的capacity为1) 在第二次调用push_back时,容量不够,此时vector会重新分配capacity为原来的2倍 vector会调用一次旧...
  • 调用拷贝构造函数进行初始化的时候,是不会调用=重载的。 // test.cpp : 定义控制台应用程序的入口点。 // //#include "stdafx.h" #include<iostream> #include<vector> #include<...
  • 由于本人较为菜鸡,专业也不是计算机,编程对我形成的概念和程序员是大相径庭,以前c++从没学到真谛,其实就是当c用的。所以,最近开始认(xia...调试中发现,在调用拷贝构造函数时,已有的类变量的size()无法赋值给新
  • 如下代码,拷贝构造函数为什么会调用3次? #include <iostream> #include <vector> using std::cout; using std::endl; using std::vector; class A { public: A(){} A(const A &a) {...
  • 为什么在自定义类时,需要重写拷贝赋值函数和拷贝构造函数? 1.理解这个问题前,先要弄明白深拷贝和浅拷贝两个概念: 如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 561
精华内容 224
关键字:

vector拷贝构造函数