c++ 副本构造函数 函数实参 形参 c++入门经典 11 17 章

 

 

11.4.9 

c++默认生成副本构造函数,但是有指针时会造成一个内存被两个指针同时指向的问题。

 

Box::Box(Box box){}

  1. 这个实参时按值传递。它是个Box对象,所以编译器需要调用 Box的副本构造函数,制作这个副本。而这个副本构造函数又是按值传递的,又需要再次调用副本构造函数,造成递归。为了避免,需要用引用。避免递归。
  2. 如果不用const,这个参数就不能接收const的对象实参,比如 const Box b; Box c{b}. 编译时会出错。

所以,所以构造类型都一样:

TYPE::TYPE(const TYPE& object){ ... }

注意,所以实参的传递是用 copy constructor,而不是 assignment operator。

  •  申明时的赋值其实是拷贝构造:比如: Box a; Box b=a;等价于 Box b{a} 或者 Box b(a);
  • 在函数的参数传递时:

             void f(Box p){};

              Box a;

              f(a);

上面语句相当于:Box p=a; 等价于 Box p{a}。这里不是调用的赋值构造,而是调用拷贝构造函数。

f(Box()) 由于传递进去个临时变量,会调用移动构造函数。

 

参考示例,好好体会:

示例1:push_back的左值引用和右值引用分开版:

把下面的代码中: #if 1全变成 #if 0.

示例2:push_back用一个 传值 的版本

// Exercising two overloads of push_back(): one for lvalue arguments, and one for rvalue arguments
#include <stdexcept>                        // For standard exception types
#include <string>                           // For std::to_string()
#include <utility>                          // For std::as_const()
#include <iostream>                         // For std::cout (used for debugging output)

template <typename T>
class Array
{
private:
    T* elements;                              // Array of type T
    size_t size;                              // Number of array elements

public:
    explicit Array(size_t arraySize = 0);     // Constructor
    Array(const Array& array);                // Copy constructor
    Array(Array&& array);                     // Move constructor
    ~Array();                                 // Destructor
    Array& operator=(const Array& rhs);       // Copy assignment operator
    Array& operator=(Array&& rhs);            // Move assignment operator
#if 1
    void push_back(T value);           // Add a new element (copied)

#else
    void push_back(const T& value);           // Add a new element (copied)
    void push_back(T&& value);                // Add a new element (moved)
#endif
    T& operator[](size_t index);              // Subscript operator
    const T& operator[](size_t index) const;  // Subscript operator-const arrays
    size_t getSize() const { return size; }   // Accessor for size
    void swap(Array& other) noexcept;         // noexcept swap member function
};

// Conventional noexcept swap non-member function
template <typename T>
void swap(Array<T>& one, Array<T>& other) noexcept
{
    one.swap(other);     // Forward to public member function
}

// Constructor
template <typename T>                      // This is a template with parameter T 
Array<T>::Array(size_t arraySize) : size{ arraySize }, elements{ new T[arraySize] }
{}

// Copy constructor
template <typename T>
Array<T>::Array(const Array& array) : Array{ array.size }
{
    std::cout << "Array of " << size << " elements copied" << std::endl;
    for (size_t i{}; i < size; ++i)
        elements[i] = array.elements[i];
}

// Move constructor
template <typename T>
Array<T>::Array(Array&& moved)
    : size{ moved.size }, elements{ moved.elements }
{
    std::cout << "Array of " << size << " elements moved" << std::endl;
    moved.elements = nullptr;          // Prevent moved from calling delete[] on elements
}

// Destructor
template <typename T>
Array<T>::~Array()
{
    delete[] elements;
}

// const subscript operator
template <typename T>
const T& Array<T>::operator[](size_t index) const
{
    if (index >= size)
        throw std::out_of_range{ "Index too large: " + std::to_string(index) };

    return elements[index];
}

// Non-const subscript operator in terms of const one
// Uses the 'const-and-back-again' idiom
template <typename T>
T& Array<T>::operator[](size_t index)
{
    return const_cast<T&>(std::as_const(*this)[index]);
}
#if 1

template <typename T>
void Array<T>::push_back(T element)
{
    Array<T> newArray(size + 1);         // Allocate a larger Array<>
    for (size_t i = 0; i < size; ++i)    // Move all existing elements...
        newArray[i] = std::move(elements[i]);

    newArray[size] = std::move(element); // Move the new one as well...

    swap(newArray);                      // ... and swap!  (noexcept)
}

#else
// Add a new element by copying it. 
// This overload is selected whenever an lvalue expression is passed to push_back().
template <typename T>
void Array<T>::push_back(const T& element)
{
    Array<T> newArray(size + 1);        // Allocate a larger Array<>
    for (size_t i = 0; i < size; ++i)   // Move all existing elements...
        newArray[i] = std::move(elements[i]);

    newArray[size] = element;           // Copy the new one...

    swap(newArray);                     // ... and swap!  (noexcept)
}

// Add a new element by moving it. 
// This overload is selected whenever an rvalue expression is passed to push_back().
template <typename T>
void Array<T>::push_back(T&& element)
{
    Array<T> newArray(size + 1);         // Allocate a larger Array<>
    for (size_t i = 0; i < size; ++i)    // Move all existing elements...
        newArray[i] = std::move(elements[i]);

    newArray[size] = std::move(element); // Move the new one as well...

    swap(newArray);                      // ... and swap!  (noexcept)
}
#endif
// Copy assignment operator in terms of the copy constructor
// Uses the 'copy-and-swap' idiom.
template <typename T>
Array<T>& Array<T>::operator=(const Array& rhs)
{
    Array<T> copy{ rhs };       // Copy ...       (could go wrong and throw an exception)
    swap(copy);               // ... and swap!  (noexcept)
    return *this;             // Return lhs
}

// Move assignment operator
template <typename T>
Array<T>& Array<T>::operator=(Array&& rhs)
{
    std::cout << "Array of " << rhs.size << " elements moved (assignment)" << std::endl;

    if (this != &rhs)            // prevent trouble with self-assignments
    {
        delete[] elements;         // delete[] all existing elements

        elements = rhs.elements;   // copy the elements pointer and the size
        size = rhs.size;

        rhs.elements = nullptr;    // make sure rhs does not delete[] elements
    }
    return *this;                // return lhs
}

// noexcept swap member function
template <typename T>
void Array<T>::swap(Array& other) noexcept
{
    std::swap(elements, other.elements);
    std::swap(size, other.size);
}


// Construct an Array<> of a given size, filled with some arbitrary string data
Array<std::string> buildStringArray(const size_t size)
{
    Array<std::string> result{ size };
    for (size_t i = 0; i < size; ++i)
        result[i] = "You should learn from your competitor, but never copy. Copy and you die.";
    return result;
}


int main()
{   
    Array<Array<std::string>> array_of_arrays;
    Array<std::string> array{ buildStringArray(1'000) };
    array_of_arrays.push_back(array); // Push an lvalue
    array.push_back("One more for good measure");
    std::cout << std::endl;
    array_of_arrays.push_back(std::move(array)); // Push an rvalue
}

 

posted @ 2021-08-31 11:24  Bigben  阅读(200)  评论(0编辑  收藏  举报