首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >实现移动构造函数的C++20 VisualStudio2022编译器优化设置

实现移动构造函数的C++20 VisualStudio2022编译器优化设置
EN

Stack Overflow用户
提问于 2022-07-10 10:35:05
回答 1查看 126关注 0票数 0

我正在探索C++20中的移动语义,使用霍顿和Van的“起始C++20从新手到专业人员”。我使用MSVisualStudio2022版本17.2.5作为我的IDE,我在"C/C++ ->优化“下尝试了几个不同的编译器优化选项,它们似乎没有任何影响。当前选择的选项是“最大优化(偏好大小) (/O1)”,应该发生的情况是,1000元素数组被移动的次数从20次减少到10次,如程序的输出所示:

如果编译器使用移动构造函数,“移动的1000个元素数组”只应打印10次。

代码语言:javascript
复制
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved
Array of 1000 elements moved

下面列出了.cpp源文件和.ixx模块文件。是否有人遇到过类似的情况,并成功地调优编译器以避免此问题?

Array.ixx

代码语言:javascript
复制
export module array;

import <stdexcept>;
import <string>;
import <utility>;
import <iostream>;

export template <typename T>
class Array
{
public:
    explicit Array(size_t size);              // Constructor
    ~Array();                                 // Destructor
    Array(const Array& array);                // Copy constructor
    Array(Array&& array);                     // Move constructor
    Array& operator=(const Array& rhs);       // Copy assignment operator
    void swap(Array& other) noexcept;         // Swap member function
    T& operator[](size_t index);              // Subscript operator
    const T& operator[](size_t index) const;  // Subscript operator-const arrays
    size_t getSize() const { return m_size; } // Accessor for m_size

private:
    T* m_elements;    // Array of type T
    size_t m_size;    // Number of array elements
};

// Constructor template
template <typename T>
Array<T>::Array(size_t size) : m_elements{ new T[size] {} }, m_size{ size }
{}

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

// Move constructor template
template <typename T>
Array<T>::Array(Array&& moved)
    : m_size{ moved.m_size }, m_elements{ moved.m_elements }
{
    std::cout << "Array of " << m_size << " elements moved" << std::endl;
    moved.m_elements = nullptr;
}

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

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

// Non-const subscript operator template 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]);
}

// Template for exception-safe copy assignment operators
// (expressed in terms of copy constructor and swap member)
template <typename T>
inline 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;
}

// Swap member function template
template <typename T>
void Array<T>::swap(Array& other) noexcept
{
    std::swap(m_elements, other.m_elements); // Swap two pointers
    std::swap(m_size, other.m_size);         // Swap the sizes
}

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

Ex18_01.cpp

代码语言:javascript
复制
import array;
import <string>;
import <vector>;


Array<std::string> buildStringArray(const size_t size)
{
    Array<std::string> result{ size };

    for (size_t i{}; i < size; ++i)
        result[i] = "You should learn from you competitor, but never copy. Copy and you die.";
    return result;
}

int main()
{
    const size_t numArrays{ 10 };
    const size_t numStringsPerArray{ 1000 };

    std::vector<Array<std::string>> vectorOfArrays;
    vectorOfArrays.reserve(numArrays);

    for (size_t i{}; i < numArrays; ++i)
    {
        vectorOfArrays.push_back(buildStringArray(numStringsPerArray));
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-10 10:46:31

正在使用移动构造函数,否则您将看到“复制”的消息,而不是“已移动的元素”。这不是优化。它是由语言保证的。编译器选项并不重要。

它不能保证,无论您使用什么样的优化设置,这一行将只打印10次。编译器可以在buildStringArray中执行NRVO (名为返回值优化),在这种情况下,std::vector内部只有10行构造,但是编译器不必应用NRVO,也不能强迫编译器这样做。如果它不应用NRVO (不管出于什么原因),那么行可能打印多达20次,因为每个return result;语句也会导致移动构造。

如果这本书声称这条线只印了10次,那就错了。但根据OP在这个问题下的评论,它将声明限定为“正常”,我想这并不是不正确的。我在编译器浏览器上的测试表明,GCC、Clang和MSVC都应用了NRVO,但我不确定将它们分离成多个翻译单元/模块会产生什么效果。

当然,如果编译器即使在启用优化的情况下也不应用NRVO,您可能会问这是否是遗漏的优化,但这纯粹是实现质量问题,而不是语言问题。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72927820

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档