【问题标题】:C++ Initiating object with array in constructorC ++在构造函数中使用数组初始化对象
【发布时间】:2021-07-12 00:08:42
【问题描述】:

我正在尝试使用数组启动对象。有没有办法用指针来做到这一点,或者我应该找到另一种方法来做到这一点。

编辑:我想用动态内存分配编写这段代码,我知道向量是解决这个问题的更好方法。

#include <iostream>

template <class t>
class die {
private:
    int sideCount;
    t* valueOfSides;
public:
    die(int side, t arr[]) {
        sideCount = side;
        valueOfSides = (t*)malloc(side * sizeof(t));
        for (int counter; counter < side; counter++) {
            valueOfSides[counter] = val[counter];
        }
    }

    ~die() {
        free(valueOfSides);
    }
};

int main() {
    die<int> sixsided(6, {1,2,3,4,5,6});
} 

【问题讨论】:

  • 您绝对应该找到一种不同的方法来做到这一点。在纯 C++ 代码中使用malloc 和free 总是会导致重大灾难。您是在哪本教科书中学会在 C++ 中使用 malloc 和 free 的?那是 C,在纯 C++ 代码中使用 malloc 和 free 从来没有正当理由。
  • 我知道 std::vector 是 c++ 声明数组的方式,但我认为这不是现在的问题
  • 当然可以。因为如果构造函数的参数是const std::vector&lt;t&gt; &amp;(模板类的其余部分也相应调整),那么会立即发生两件事。 1) 构造函数的第二个参数没有任何理由,明确给出值的数量,因为现在可以从t.size() 轻松获得,并且 2)die&lt;int&gt; sixsided({1,2,3,4,5,6}); 将实际编译!我仍然很好奇哪本 C++ 教科书声称正确的方法是使用 malloc 和 free。
  • 这是 C 题还是 C++ 题?
  • 这与“动态内存分配”无关,而是与 C++ 语法有关。不能从花括号初始化列表中推断出指针。发生任何远程类似情况的唯一上下文是字符串文字,其中"literal string" 被推导出为const char [],然后衰减为const char *。

标签: c++ arrays class constructor


【解决方案1】:

使用更多的 C 技术可以做到这一点的一种方法是变量参数列表:

#include <cstdarg>
#include <iostream>

template <class t>
class die {
private:
    int sideCount;
    t* valueOfSides;
public:
    die(int side, ...) {
        sideCount = side;
        valueOfSides = new t[side];

        va_list args;
        va_start(args, side);
        for (int counter = 0; counter < side; counter++) {
            valueOfSides[counter] = va_arg(args, t);
        }
        va_end(args);
    }

    ~die() {
        delete[] valueOfSides;
    }
};

int main() {
    die<int> sixsided(6, 1,2,3,4,5,6);
}

您不是传递数组,而是单独传递参数(即不需要临时数组)并使用va_list 来访问它们。

此外,对 malloc 和 free 的调用被替换为 new 和 delete,这是 C++ 分配和释放内存的方式。

【讨论】:

    【解决方案2】:

    C++ 解决方案:

    
    template <class t>
    class die {
    private:
        int sideCount;
        t* valueOfSides;
    public:
        die(int side, t arr[]) {
            sideCount = side;
            valueOfSides = new T[side]
            for (int counter = 0; counter < side; counter++) { //always initialize variables
                valueOfSides[i] = arr[i];
            }
        }
    
        ~die() {
            delete[] valueOfSides;
        }
    };
    
    int main() {
        int arr[6] = { 1,2,3,4,5,6 };
        die<int> sixsided(6, arr);
    }
    

    new 运算符类似于malloc,delete 和delete[] 运算符类似于free。它们是动态分配器。

    C 解决方案:

    template <class t>
    class die {
    private:
        int sideCount;
        t* valueOfSides;
    public:
        die(int side, t arr[]) {
            sideCount = side;
            valueOfSides = (t*)malloc(side * sizeof(t));
            for (int counter = 0; counter < side; counter++) { //always initialize variables
                valueOfSides[i] = arr[i];
            }
        }
    
        ~die() {
            free(valueOfSides);
        }
    };
    
    int main() {
        int arr[6] = { 1,2,3,4,5,6 };
        die<int> sixsided(6, arr);
    }
    

    注意:在 C 中,&lt;iostream&gt; 标头不起作用,这仅适用于 C++。

    还有其他容器,即std::vector,可以工作,但这是您的答案的解决方案。

    【讨论】:

    • 您的 C++ 和 C 解决方案都有 2 次内存泄漏、两次删除,并假定类型是默认可构造和可复制分配的。
    • @MooingDuck,大部分都在原始代码中,我只是修复了代码以满足问题。内存泄漏和双重删除到底在哪里?
    • 缺少die::operator= 会导致内存泄漏和双重删除。如果t::operator= 抛出异常,还会发生第二次内存泄漏。
    • @MooingDuck,是的,但这又是在原始代码中。我所做的只是回答问题。如果出现问题,OP 可以提出另一个问题,对吗?如果我错了,请纠正我并编辑我的代码
    【解决方案3】:

    正确的做法是

    std::vector<t> valueOfSides;
    
    template<size_t len> die(t (&arr)[len])
    : valueOfSides(std::begin(arr), std::end(arr))
    {}
    

    或

    std::vector<t> valueOfSides;
    
    die(std::initializer_list<t> arr) : valueOfSides(arr) {}
    

    我想。虽然真的,最好的答案是

    std::vector<t> valueOfSides;
    
    die(std::vector<t> arr) : valueOfSides(std::move(arr)) {}
    

    在 C++ 中永远不要使用原始指针来拥有自己的内存,并且实际上永远不要使用 new 或 malloc。实际上,由于滥用malloc,您的代码中有未定义的行为。


    如果你真的疯了,或者在做作业,可以用原始指针来完成,但我怀疑如果没有测试和编译器,我能否完全正确。

    template<class t>
    class die {
    private:
        int sideCount;
        t* valueOfSides;
    public:
        die(int side, t* arr) {
            sideCount = 0;
            std::size_t buffer_size = sizeof(t)*side;
            char* buffer;
            try {
                buffer = new char[side];
                valueOfSides = reinterpret_cast<t*>(buffer);
                for(int i=0; i<side; i++) {
                    new(valueOfSides+i)t(arr[i]);
                    sideCount++;
                }
            } catch(...) {
                for(int i=sideCount; i>=0; i--)
                    (valueOfSides+i)->~t();
                delete[]buffer;
                throw;
            }
        }
        die& operator=(die&& rhs) {
            sideCount = rhs.sideCount;
            valueOfSides = rhs.valueOfSides;
            rhs.valueOfSides = nullptr;
            rhs.sideCount = 0;
            return *this;
        }
        //die& operator=(const die& rhs) not shown because its super hard.
    
        ~die() {
            for(int i=sideCount; i>=0; i--)
                (valueOfSides+i)->~t();
            delete[]reinterpret_cast<char*>(valueOfSides);
        }
    };
    

    正如我们之前所说,把这些东西做好是非常困难的。使用std::vector。

    【讨论】:

      【解决方案4】:

      使用std::vector。

      #include <iostream>
      #include <initalizer_list>
      #include <vector>
      
      template<class T>
      class die {
      public:
          die() = default;
          die(std::initializer_list<T> list)
          : sides{list}
          { /* DO NOTHING */ }
      private:
          std::vector<T> sides{};
      };
      
      int main() {
          die<int> sixsided({1,2,3,4,5,6});
      } 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-10
        • 1970-01-01
        • 2021-07-26
        • 1970-01-01
        • 1970-01-01
        • 2021-11-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多