স্টাড :: ভেক্টর যুক্ত করার সময় শ্রেণীর ক্ষেত্রগুলির সাথে অদ্ভুত আচরণ


31

নিম্নলিখিত পরিস্থিতিতে আমি কিছু খুব অদ্ভুত আচরণ (ঝনঝন এবং জিসিসিতে) পেয়েছি। আমার কাছে একটি ভেক্টর রয়েছে, nodesযার একটি উপাদান রয়েছে, ক্লাসের একটি উদাহরণ Node। আমি তারপরে একটি ফাংশন বলি যা ভেক্টরে nodes[0]একটি নতুন যুক্ত Nodeকরে। নতুন নোড যুক্ত করা হলে কলিং অবজেক্টের ক্ষেত্রগুলি পুনরায় সেট করা হয়! তবে, ফাংশনটি শেষ হয়ে গেলে তারা আবার স্বাভাবিক অবস্থায় ফিরে আসবে বলে মনে হয়।

আমি বিশ্বাস করি এটি একটি ন্যূনতম প্রজননযোগ্য উদাহরণ:

#include <iostream>
#include <vector>

using namespace std;

struct Node;
vector<Node> nodes;

struct Node{
    int X;
    void set(){
        X = 3;
        cout << "Before, X = " << X << endl;
        nodes.push_back(Node());
        cout << "After, X = " << X << endl;
    }
};

int main() {
    nodes = vector<Node>();
    nodes.push_back(Node());

    nodes[0].set();
    cout << "Finally, X = " << nodes[0].X << endl;
}

কোন ফলাফল

Before, X = 3
After, X = 0
Finally, X = 3

যদিও আপনি আশা করতে পারেন এক্সটি প্রক্রিয়া দ্বারা অপরিবর্তিত থাকবে।

অন্যান্য জিনিস আমি চেষ্টা করেছি:

  • যদি আমি কোনও Nodeঅভ্যন্তর যুক্ত করে এমন লাইনটি সরিয়ে ফেলি set(), তবে এটি প্রতিবার এক্স = 3 আউটপুট করে।
  • যদি আমি একটি নতুন তৈরি করে Nodeএবং ( Node p = nodes[0]) এ এটি কল করি তবে আউটপুট 3, 3, 3 হবে
  • যদি আমি একটি রেফারেন্স তৈরি করি Nodeএবং এটিতে কল করি ( Node &p = nodes[0]) তবে আউটপুট 3, 0, 0 হয় (ভেক্টর পুনরায় আকার দেওয়ার পরে রেফারেন্সটি হারিয়ে যায় বলে সম্ভবত এটিই হয়?)

এই অপরিবর্তিত আচরণ কি কোনও কারণে? কেন?


4
En.cppreferences.com/w/cpp/container/vector/push_back দেখুন । আপনি reserve(2)কল করার আগে যদি ভেক্টরকে ডেকে আনা set()হত তবে এটি সংজ্ঞায়িত আচরণ হবে। কিন্তু এর মতো একটি ফাংশন লেখার setজন্য reserveঅপরিজ্ঞাত আচরণটি এড়াতে খারাপ কল্পনা করার জন্য ব্যবহারকারীকে কল করার আগে যথাযথ আকারের প্রয়োজন হয় , তাই এটি করবেন না।
জনফিলাউ

উত্তর:


39

আপনার কোডের আচরণ নির্ধারিত রয়েছে। ভিতরে

void set(){
    X = 3;
    cout << "Before, X = " << X << endl;
    nodes.push_back(Node());
    cout << "After, X = " << X << endl;
}

অ্যাক্সেস Xসত্যই this->Xএবং thisভেক্টরের সদস্যের পয়েন্টার। আপনি যখন nodes.push_back(Node());ভেক্টরে কোনও নতুন উপাদান যুক্ত করেন এবং সেই প্রক্রিয়াটি পুনরায় স্থান দেয়, যা ভেক্টরের উপাদানগুলির জন্য সমস্ত পুনরাবৃত্তকারী, পয়েন্টার এবং রেফারেন্সকে অবৈধ করে দেয়। এর মানে

cout << "After, X = " << X << endl;

এমনটি ব্যবহার করা thisহচ্ছে যা আর বৈধ নয়।


push_backইতিমধ্যে সংজ্ঞায়িত আচরণকে কল করা হচ্ছে (যেহেতু আমরা তখন অবৈধযুক্ত সদস্য ফাংশনে আছি this) বা thisপয়েন্টারটি ব্যবহার করার পরে প্রথমবার ইউবি ঘটে যায় ? এটা কি সম্ভব হবে return 42;?
n314159

3
@ n314159 উদাহরণ nodesথেকে স্বতন্ত্র Nodeতাই কল করার ক্ষেত্রে কোনও ইউবি নেই push_back। ইউবি পরে অবৈধ পয়েন্টার ব্যবহার করছে।
নাথান অলিভার

@ n314159 void set(Node* this)এটি কল্পনা করার একটি ভাল উপায় একটি ফাংশনটি কল্পনা করা , এটি কোনও অবৈধ পয়েন্টার বা free()ফাংশনে এটি পাস করা অপরিচিত নয় । আমি নিশ্চিত নই তবে আমি ধারণা করি যে ((Node*) nullptr)->set()আপনি যদি ব্যবহার না করেন thisএবং পদ্ধতিটি ভার্চুয়াল না হয় তবেও সংজ্ঞায়িত করা হয়।
DutChen18

আমি মনে করি না ((Node *) nullptr)->set()এটি ঠিক আছে, যেহেতু এইটি নাল পয়েন্টারকে অবজ্ঞায়িত করে (সমান হিসাবে এটি লেখার সময় আপনি কোরিটি স্পষ্ট দেখতে পাচ্ছেন (*((Node *) nullptr)).set();)।
n314159

1
@ ডেডুপ্লিকেটর আমি শব্দটি আপডেট করেছি।
নাথান অলিভার

15
nodes.push_back(Node());

ভেক্টরটিকে পুনরায় স্থান দেবে, সুতরাং এর ঠিকানা পরিবর্তন করে nodes[0], তবে thisআপডেট করা হয়নি। এই কোডটি দিয়ে পদ্ধতিটি
প্রতিস্থাপনের চেষ্টা করুন set:

    void set(){
        X = 3;
        cout << "Before, X = " << X << endl;
        cout << "Before, this = " << this << endl;
        cout << "Before, &nodes[0] = " << &nodes[0] << endl;
        nodes.push_back(Node());
        cout << "After, X = " << X << endl;
        cout << "After, this = " << this << endl;
        cout << "After, &nodes[0] = " << &nodes[0] << endl;
    }

&nodes[0]কল করার পরে কীভাবে আলাদা তা লক্ষ্য করুন push_back

-fsanitize=addressএটি ধরা পড়বে এবং এমনকি আপনি যদি সংকলন করেন তবে মেমরিটি কোন লাইনে মুক্ত হয়েছিল তা আপনাকে জানিয়ে দেবে -g

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.