is a memcpy() equivalent to the default copy constructor?

Discussion in 'C++' started by jonathan cano, Apr 13, 2005.

  1. QUESTION:

    In practice, lines 36 and 37 below are usually equivalent to the
    default copy constructor (.e.g line 33). My questions are:

    (a) Does ISO 14882 guarantee that lines 36 and 37 are equivalent
    to executing the default copy constructor (i.e. lines 33)?

    (b) If not, is the behavior for lines 36-39 well defined by the
    standard?

    While all C++ compilers I know of implement virtual functions by
    storing a pointer to a vtable in the object the standard doesn't talk
    about implementation details like this ...

    Regards,
    --jfc

    1 #include <iostream>
    2 #include <cstdlib>
    3
    4 class foo {
    5 public:
    6 int i;
    7 foo(): i(3) {}
    8 virtual void f() { std::cout << "foo" << std::endl; }
    9 virtual ~foo() {};
    10 };
    11
    12 class bish : public foo {
    13 public:
    14 int j;
    15 double d;
    16
    17 bish(int p): j(p), d(0.0) {}
    18 void f() { std::cout << "bish" << std::endl; }
    19 ~bish() {};
    20 };
    21
    22 int
    23 main(int argc,char *argv[])
    24 {
    25 char buf1[sizeof(bish)];
    26
    27 bish b1(99);
    28
    29 // consttruct with placement new.
    30 bish * b2 = new((void *)buf1) bish(42);
    31
    32 // copying with the default copy ctor
    33 bish b3(b1);
    34
    35 // equivalent to copy construction?
    36 bish * b4 = (bish *) new char[sizeof(bish)];
    37 memcpy((char *)b4, (char *)&b1, sizeof(bish));
    38
    39 b4->f();
    40 }
    41


    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
     
    jonathan cano, Apr 13, 2005
    #1
    1. Advertising

  2. "jonathan cano" <> skrev i en meddelelse
    news:...
    > QUESTION:
    >
    > In practice, lines 36 and 37 below are usually equivalent to the
    > default copy constructor (.e.g line 33). My questions are:
    >
    > (a) Does ISO 14882 guarantee that lines 36 and 37 are equivalent
    > to executing the default copy constructor (i.e. lines 33)?


    Nope.

    >
    > (b) If not, is the behavior for lines 36-39 well defined by the
    > standard?


    You could say so. The behaviour is "undefined".
    You also seem to have a problem with alignment. buf1 will NOT be aligned
    properly for a foo structure, and I do not believe that bish4 is required to
    be properly aligned (although i am not completely sure here).

    >
    > While all C++ compilers I know of implement virtual functions by
    > storing a pointer to a vtable in the object the standard doesn't talk
    > about implementation details like this ...

    Correct.
    >
    > Regards,
    > --jfc
    >

    [snip]

    /Peter


    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
     
    Peter Koch Larsen, Apr 13, 2005
    #2
    1. Advertising

  3. Hi,

    jonathan cano wrote:

    > In practice, lines 36 and 37 below are usually equivalent to the
    > default copy constructor (.e.g line 33). My questions are:
    >
    > (a) Does ISO 14882 guarantee that lines 36 and 37 are equivalent
    > to executing the default copy constructor (i.e. lines 33)?


    No, there is no such guarantee.
    The most problematic are virtual functions in the foo class, although it
    might as weel appear to work on some platforms.

    > (b) If not, is the behavior for lines 36-39 well defined by the
    > standard?


    No. You cannot memcpy non-POD types.

    Moreover, I think there is no guarantee that new char[] will allocate
    the memory block that is correctly aligned for bish (b4 in your code).
    Certainly, there is no such guarantee for local char[] arrays (buf1 in
    your code).

    This could be another problem in your code. Not what you're asking
    about, but still important.

    --
    Maciej Sobczak : http://www.msobczak.com/
    Programming : http://www.msobczak.com/prog/

    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
     
    Maciej Sobczak, Apr 13, 2005
    #3
  4. jonathan cano wrote:
    > QUESTION:
    >
    > In practice, lines 36 and 37 below are usually equivalent to the
    > default copy constructor (.e.g line 33). My questions are:
    >
    > (a) Does ISO 14882 guarantee that lines 36 and 37 are equivalent
    > to executing the default copy constructor (i.e. lines 33)?
    >
    > (b) If not, is the behavior for lines 36-39 well defined by the
    > standard?
    >
    > While all C++ compilers I know of implement virtual functions by
    > storing a pointer to a vtable in the object the standard doesn't talk
    > about implementation details like this ...
    >
    > Regards,
    > --jfc
    >

    [snip]

    > 30 bish * b2 = new((void *)buf1) bish(42);


    > 36 bish * b4 = (bish *) new char[sizeof(bish)];
    > 37 memcpy((char *)b4, (char *)&b1, sizeof(bish));


    Copy construction is a member-wise operation; the object is initialized
    as if the copy constructors of each member where invoked. Typically,
    the copy constructors of each member are invoked.

    For certain classes (PODs), this may be equivalent to memcpy, but in
    general it is not.

    In the case of classes with virtual functions, memcpy is almost
    certainly the wrong thing; for example:

    struct A { virtual f() { cout << "A::f"; } };
    struct B : public A { virtual f() { cout << "B::f"; } };

    B b;
    A a(b); // copy ctor A::A is called here.

    In this case, memcpying some part of B into A is, at best, Undefined
    Behavior.
    --
    A. Kanawati


    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
     
    Antoun Kanawati, Apr 13, 2005
    #4
  5. jonathan  cano

    Joel Guest

    In general, the default copy constructor calls operator= on each data
    member of the class, so if you have, for instance, a shared pointer in
    your class, the memcpy wouldn't update the count, while the default
    copy constructor would.

    In this specific example, you would probably be okay, in practical
    terms, but according to the standard, the results are undefined.

    Joel Redman


    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
     
    Joel, Apr 13, 2005
    #5
  6. jonathan  cano

    Old Wolf Guest

    Joel wrote:
    > In general, the default copy constructor calls operator= on
    > each data member of the class


    Actually it calls the copy constructor on each data member.

    The default operator= would call operator= on its data members.


    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
     
    Old Wolf, Apr 14, 2005
    #6
  7. jonathan  cano

    RH Guest

    Note that modern compilers (e.g. Intel's or HP's) have a phase that
    tries to determine which would be the best way to default copy an
    object. memcpy() is usually not as good as member-by-member copy for
    smaller objects, but better for larger objects.

    The compilers employ all kinds of heuristics to make this fast. If you
    profile-see a bottleneck there - try a better compiler ;-)

    -- RH


    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
     
    RH, Apr 14, 2005
    #7
  8. jonathan  cano

    RH Guest

    Note that modern compilers (e.g. Intel's or HP's) have a phase that
    tries to determine which would be the best way to default copy an
    object. memcpy() is usually not as good as member-by-member copy for
    smaller objects, but better for larger objects.

    The compilers employ all kinds of heuristics to make this fast. If you
    profile-see a bottleneck there - try a better compiler ;-)

    -- RH


    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
     
    RH, Apr 14, 2005
    #8
  9. Joel wrote:
    > In general, the default copy constructor calls operator= on each data
    > member of the class, so if you have, for instance, a shared pointer in
    > your class, the memcpy wouldn't update the count, while the default
    > copy constructor would.


    Operator= is NOT copy construction. The copy-ctor call the copy-ctors
    of the members. To call operator= you need two already constructed
    objects.
    --
    A. Kanawati


    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
     
    Antoun Kanawati, Apr 14, 2005
    #9
  10. "Joel" <> wrote in message
    news:...

    > In general, the default copy constructor calls operator= on each data
    > member of the class...


    No, it doesn't -- it calls the copy constructor on each data member of the
    class.


    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
     
    Andrew Koenig, Apr 14, 2005
    #10
  11. jonathan  cano

    Joel Guest

    I sit corrected. .

    The important point is that memcpy is not called, to prevent improper
    construction of things with nontrivial construction. In the event that
    you do have a trivial construction, the compiler may very well optimize
    this to a memcpy, but you cannot say that a-priori.

    Joel


    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
     
    Joel, Apr 19, 2005
    #11
  12. Maciej Sobczak write "ms>":
    ms> Moreover, I think there is no guarantee that new char[] will
    ms> allocate the memory block that is correctly aligned for bish (b4
    ms> in your code).> Certainly, there is no such guarantee for local
    ms> char[] arrays (buf1 in your code).

    Thanks for pointing that out.

    presumably my original code sample could be fixed like this:

    25 char buf1[sizeof(bish) + ALIGNMENT_BYTES];
    + char *cp = buf1;

    + while (not_aligned(cp)) ++cp;

    30 bish * b2 = new((void *)cp) bish(42);

    Which leaves the question: Is there a portable way to align a pointer
    so that it meets a platforms strictest alignment requirements or is
    such code doomed to non-portability?

    It seems technically feasible that this could be included in a
    language standard although time and/or politics may have kept it out of
    ISO 14882.

    --jfc


    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
     
    jonathan cano, Apr 19, 2005
    #12
  13. jonathan cano wrote:
    > Maciej Sobczak write "ms>":
    > ms> Moreover, I think there is no guarantee that new char[] will
    > ms> allocate the memory block that is correctly aligned for bish (b4
    > ms> in your code).> Certainly, there is no such guarantee for local
    > ms> char[] arrays (buf1 in your code).
    >
    > Thanks for pointing that out.
    >
    > presumably my original code sample could be fixed like this:
    >
    > 25 char buf1[sizeof(bish) + ALIGNMENT_BYTES];
    > + char *cp = buf1;
    >
    > + while (not_aligned(cp)) ++cp;
    >
    > 30 bish * b2 = new((void *)cp) bish(42);
    >
    > Which leaves the question: Is there a portable way to align a pointer
    > so that it meets a platforms strictest alignment requirements or is
    > such code doomed to non-portability?
    >
    > It seems technically feasible that this could be included in a
    > language standard although time and/or politics may have kept it out of
    > ISO 14882.
    >
    > --jfc
    >
    >
    > [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    > [ comp.lang.c++.moderated. First time posters: Do this! ]
    >


    From 'man malloc':

    "For calloc() and malloc(), the value returned is a pointer to the
    allocated memory, which is suitably aligned for any kind of variable,
    or NULL if the request fails."

    So, memory obtained via malloc() and family is suitably aligned
    for any type, including pointers.

    Regards,
    Larry


    --
    Anti-spam address, change each 'X' to '.' to reply directly.
     
    Larry I Smith, Apr 20, 2005
    #13
  14. jonathan cano wrote:

    > Maciej Sobczak write "ms>":
    > ms> Moreover, I think there is no guarantee that new char[] will
    > ms> allocate the memory block that is correctly aligned for bish (b4
    > ms> in your code).> Certainly, there is no such guarantee for local
    > ms> char[] arrays (buf1 in your code).
    >
    > Thanks for pointing that out.
    >
    > presumably my original code sample could be fixed like this:
    >
    > 25 char buf1[sizeof(bish) + ALIGNMENT_BYTES];
    > + char *cp = buf1;
    >
    > + while (not_aligned(cp)) ++cp;
    >
    > 30 bish * b2 = new((void *)cp) bish(42);


    The only "small issue" is to compute ALIGNMENT_BYTES and implement the
    not_aligned() predicate - note that it depends on the *type* you want to
    align.
    Even experts brake their fingers on this.

    Certainly, malloc() and realloc() are required to return a pointer that
    meets the strictest alignment guarantee for all fundamental types.
    In practice, it should safely work for classes as well.

    --
    Maciej Sobczak : http://www.msobczak.com/
    Programming : http://www.msobczak.com/prog/

    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
     
    Maciej Sobczak, Apr 20, 2005
    #14
  15. "Larry I Smith" <> skrev i en meddelelse
    news:Nzi9e.17695$jd6.749@trnddc07...
    > jonathan cano wrote:
    >> Maciej Sobczak write "ms>":
    >> ms> Moreover, I think there is no guarantee that new char[] will
    >> ms> allocate the memory block that is correctly aligned for bish (b4
    >> ms> in your code).> Certainly, there is no such guarantee for local
    >> ms> char[] arrays (buf1 in your code).
    >>
    >> Thanks for pointing that out.
    >>
    >> presumably my original code sample could be fixed like this:
    >>
    >> 25 char buf1[sizeof(bish) + ALIGNMENT_BYTES];
    >> + char *cp = buf1;
    >>
    >> + while (not_aligned(cp)) ++cp;
    >>
    >> 30 bish * b2 = new((void *)cp) bish(42);
    >>
    >> Which leaves the question: Is there a portable way to align a pointer
    >> so that it meets a platforms strictest alignment requirements or is
    >> such code doomed to non-portability?
    >>
    >> It seems technically feasible that this could be included in a
    >> language standard although time and/or politics may have kept it out of
    >> ISO 14882.
    >>
    >> --jfc
    >>
    >>
    >> [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    >> [ comp.lang.c++.moderated. First time posters: Do this! ]
    >>

    >
    > From 'man malloc':
    >
    > "For calloc() and malloc(), the value returned is a pointer to the
    > allocated memory, which is suitably aligned for any kind of variable,
    > or NULL if the request fails."
    >
    > So, memory obtained via malloc() and family is suitably aligned
    > for any type, including pointers.


    This is C, not C++. For C++ operator new only guarantees suitable alignment
    for the type one is newing for.

    /Peter
    >
    > Regards,
    > Larry
    >
    >
    > --
    > Anti-spam address, change each 'X' to '.' to reply directly.
     
    Peter Koch Larsen, Apr 20, 2005
    #15
  16. Peter Koch Larsen wrote:
    > "Larry I Smith" <> skrev i en meddelelse
    > news:Nzi9e.17695$jd6.749@trnddc07...
    >>jonathan cano wrote:
    >>>Maciej Sobczak write "ms>":
    >>>ms> Moreover, I think there is no guarantee that new char[] will
    >>>ms> allocate the memory block that is correctly aligned for bish (b4
    >>>ms> in your code).> Certainly, there is no such guarantee for local
    >>>ms> char[] arrays (buf1 in your code).
    >>>
    >>>Thanks for pointing that out.
    >>>
    >>>presumably my original code sample could be fixed like this:
    >>>
    >>> 25 char buf1[sizeof(bish) + ALIGNMENT_BYTES];
    >>> + char *cp = buf1;
    >>>
    >>> + while (not_aligned(cp)) ++cp;
    >>>
    >>> 30 bish * b2 = new((void *)cp) bish(42);
    >>>
    >>>Which leaves the question: Is there a portable way to align a pointer
    >>>so that it meets a platforms strictest alignment requirements or is
    >>>such code doomed to non-portability?
    >>>
    >>>It seems technically feasible that this could be included in a
    >>>language standard although time and/or politics may have kept it out of
    >>>ISO 14882.
    >>>
    >>>--jfc
    >>>
    >>>
    >>> [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    >>> [ comp.lang.c++.moderated. First time posters: Do this! ]
    >>>

    >>From 'man malloc':
    >>
    >>"For calloc() and malloc(), the value returned is a pointer to the
    >>allocated memory, which is suitably aligned for any kind of variable,
    >>or NULL if the request fails."
    >>
    >>So, memory obtained via malloc() and family is suitably aligned
    >>for any type, including pointers.

    >
    > This is C, not C++. For C++ operator new only guarantees suitable alignment
    > for the type one is newing for.
    >
    > /Peter
    >>Regards,
    >>Larry
    >>
    >>
    >>--
    >>Anti-spam address, change each 'X' to '.' to reply directly.

    >
    >


    IIRC, the 'C' functions are part of C++.

    Regards,
    Larry

    --
    Anti-spam address, change each 'X' to '.' to reply directly.
     
    Larry I Smith, Apr 21, 2005
    #16
  17. "Larry I Smith" <> skrev i en meddelelse
    news:WHB9e.24712$jd6.18946@trnddc07...
    > Peter Koch Larsen wrote:
    >> "Larry I Smith" <> skrev i en meddelelse
    >> news:Nzi9e.17695$jd6.749@trnddc07...
    >>>jonathan cano wrote:
    >>>>Maciej Sobczak write "ms>":
    >>>>ms> Moreover, I think there is no guarantee that new char[] will
    >>>>ms> allocate the memory block that is correctly aligned for bish (b4
    >>>>ms> in your code).> Certainly, there is no such guarantee for local
    >>>>ms> char[] arrays (buf1 in your code).
    >>>>
    >>>>Thanks for pointing that out.
    >>>>
    >>>>presumably my original code sample could be fixed like this:
    >>>>
    >>>> 25 char buf1[sizeof(bish) + ALIGNMENT_BYTES];
    >>>> + char *cp = buf1;
    >>>>
    >>>> + while (not_aligned(cp)) ++cp;
    >>>>
    >>>> 30 bish * b2 = new((void *)cp) bish(42);
    >>>>
    >>>>Which leaves the question: Is there a portable way to align a pointer
    >>>>so that it meets a platforms strictest alignment requirements or is
    >>>>such code doomed to non-portability?
    >>>>
    >>>>It seems technically feasible that this could be included in a
    >>>>language standard although time and/or politics may have kept it out of
    >>>>ISO 14882.
    >>>>
    >>>>--jfc
    >>>>
    >>>>
    >>>> [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    >>>> [ comp.lang.c++.moderated. First time posters: Do this! ]
    >>>>
    >>>From 'man malloc':
    >>>
    >>>"For calloc() and malloc(), the value returned is a pointer to the
    >>>allocated memory, which is suitably aligned for any kind of variable,
    >>>or NULL if the request fails."
    >>>
    >>>So, memory obtained via malloc() and family is suitably aligned
    >>>for any type, including pointers.

    >>
    >> This is C, not C++. For C++ operator new only guarantees suitable
    >> alignment
    >> for the type one is newing for.
    >>
    >> /Peter
    >>>Regards,
    >>>Larry
    >>>
    >>>
    >>>--
    >>>Anti-spam address, change each 'X' to '.' to reply directly.

    >>
    >>

    >
    > IIRC, the 'C' functions are part of C++.
    >

    Of course, but the OP specifically used new [], not malloc. If you read the
    C++ standard, you will note that new does not have to be implemented via
    malloc.

    /Peter
    > Regards,
    > Larry
    >
    > --
    > Anti-spam address, change each 'X' to '.' to reply directly.
     
    Peter Koch Larsen, Apr 21, 2005
    #17
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Aire
    Replies:
    3
    Views:
    486
    Mike Wahler
    Jan 25, 2004
  2. ali
    Replies:
    4
    Views:
    619
    David Harmon
    Mar 5, 2007
  3. Generic Usenet Account
    Replies:
    10
    Views:
    2,341
  4. mthread

    memcpy equivalent in C++

    mthread, Nov 19, 2008, in forum: C++
    Replies:
    14
    Views:
    3,675
    Bill Davy
    Dec 1, 2008
  5. cinsk
    Replies:
    35
    Views:
    2,725
    James Kanze
    Oct 11, 2010
Loading...

Share This Page